1 /*******************************************************
2 
3  bdimad_dev.c
4 
5  Author: bdSound Development Team (techsupport@bdsound.com)
6 
7  Date: 12/03/2015
8  Version 2.0.0 rev.1618
9 
10  Copyright (c) 2015 bdSound s.r.l. (www.bdsound.com)
11  All Rights Reserved.
12 
13  *******************************************************/
14 
15 #include <pjmedia-audiodev/audiodev_imp.h>
16 #include <pj/assert.h>
17 #include <pj/log.h>
18 #include <pj/os.h>
19 #include <pj/string.h>
20 #include <pj/unicode.h>
21 #include <pjmedia/errno.h>
22 
23 #if defined(PJMEDIA_AUDIO_DEV_HAS_BDIMAD) && PJMEDIA_AUDIO_DEV_HAS_BDIMAD != 0
24 
25 #include <math.h>
26 #include <wchar.h>
27 
28 /**************************
29 *           bdIMAD
30 ***************************/
31 #include  "../../third_party/bdsound/include/bdimad.h"
32 
33 /* Maximum supported audio devices */
34 #define BD_IMAD_MAX_DEV_COUNT               100
35 /* Maximum supported device name */
36 #define BD_IMAD_MAX_DEV_LENGTH_NAME         256
37 /* Only mono mode */
38 #define BD_IMAD_MAX_CHANNELS                1
39 /* Frequency default value (admitted 8000 Hz, 16000 Hz, 32000 Hz, 44100 Hz and 48000 Hz) */
40 #define BD_IMAD_DEFAULT_FREQ                48000
41 /* Default milliseconds per buffer */
42 #define BD_IMAD_MSECOND_PER_BUFFER          16
43 /* Only for supported systems */
44 #define BD_IMAD_STARTING_INPUT_VOLUME       50
45 /* Only for supported systems */
46 #define BD_IMAD_STARTING_OUTPUT_VOLUME      100
47 /* Diagnostic Enable/Disable */
48 #define BD_IMAD_DIAGNOSTIC                  BD_IMAD_DIAGNOSTIC_DISABLE
49 
50 /* Diagnostic folder path */
51 #define BD_IMAD_DIAGNOSTIC_PATH  "/mnt/sdcard/MUSIC/"
52 
53 static wchar_t bdImadPjDiagnosticFolderPath[200];
54 
55 #define THIS_FILE            "bdimad_dev.c"
56 
57 /* BD device info */
58 struct bddev_info
59 {
60     pjmedia_aud_dev_info    info;
61     unsigned            deviceId;
62 };
63 
64 /* BD factory */
65 struct bd_factory
66 {
67     pjmedia_aud_dev_factory  base;
68     pj_pool_t                *base_pool;
69     pj_pool_t                *pool;
70     pj_pool_factory          *pf;
71     unsigned                 dev_count;
72     struct bddev_info        *dev_info;
73 };
74 
75 /* Sound stream. */
76 struct bd_stream
77 {
78     /** Base stream.                    */
79     pjmedia_aud_stream   base;
80     /** Settings.                       */
81     pjmedia_aud_param    param;
82     /** Memory pool.                    */
83     pj_pool_t           *pool;
84 
85     /** Capture callback.               */
86     pjmedia_aud_rec_cb   rec_cb;
87     /** Playback callback.              */
88     pjmedia_aud_play_cb  play_cb;
89     /** Application data.               */
90     void                *user_data;
91 
92     /** Frame format                    */
93     pjmedia_format_id    fmt_id;
94     /** Silence pattern                 */
95     pj_uint8_t           silence_char;
96     /** Bytes per frame                 */
97     unsigned             bytes_per_frame;
98     /** Samples per frame               */
99     unsigned		 samples_per_frame;
100     /** Channel count	                 */
101     int			 channel_count;
102 
103     /** Extended frame buffer           */
104     pjmedia_frame_ext   *xfrm;
105     /** Total ext frm size              */
106     unsigned             xfrm_size;
107 
108     /** Check running variable          */
109     int                  go;
110 
111     /** Timestamp iterator for capture  */
112     pj_timestamp         timestampCapture;
113     /** Timestamp iterator for playback */
114     pj_timestamp         timestampPlayback;
115 
116     /** bdIMAD current session instance */
117     bdIMADpj             bdIMADpjInstance;
118     /** bdIMAD current session settings */
119     bdIMADpj_Setting_t  *bdIMADpjSettingsPtr;
120     /** bdIMAD current session warnings */
121     bdIMADpj_Warnings_t *bdIMADpjWarningPtr;
122 
123     pj_bool_t		 quit_flag;
124 
125     pj_bool_t		 rec_thread_exited;
126     pj_bool_t		 rec_thread_initialized;
127     pj_thread_desc	 rec_thread_desc;
128     pj_thread_t		*rec_thread;
129 
130     pj_bool_t		 play_thread_exited;
131     pj_bool_t		 play_thread_initialized;
132     pj_thread_desc	 play_thread_desc;
133     pj_thread_t		*play_thread;
134 
135     /* Sometime the record callback does not return framesize as configured
136      * (e.g: in OSS), while this module must guarantee returning framesize
137      * as configured in the creation settings. In this case, we need a buffer
138      * for the recorded samples.
139      */
140     pj_int16_t		*rec_buf;
141     unsigned		 rec_buf_count;
142 
143     /* Sometime the player callback does not request framesize as configured
144      * (e.g: in Linux OSS) while sound device will always get samples from
145      * the other component as many as configured samples_per_frame.
146      */
147     pj_int16_t		*play_buf;
148     unsigned		 play_buf_count;
149 };
150 
151 /* Prototypes */
152 
153 // pjmedia_aud_dev_factory_op
154 static pj_status_t factory_init(pjmedia_aud_dev_factory *f);
155 static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f);
156 static unsigned    factory_get_dev_count(pjmedia_aud_dev_factory *f);
157 static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,
158 					unsigned index,
159 					pjmedia_aud_dev_info *info);
160 static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
161 					 unsigned index,
162 					 pjmedia_aud_param *param);
163 static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
164 					 const pjmedia_aud_param *param,
165 					 pjmedia_aud_rec_cb rec_cb,
166 					 pjmedia_aud_play_cb play_cb,
167 					 void *user_data,
168 					 pjmedia_aud_stream **p_aud_strm);
169 static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f);
170 
171 // pjmedia_aud_stream_op
172 static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
173 				    pjmedia_aud_param *param);
174 static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
175 				  pjmedia_aud_dev_cap cap,
176 				  void *value);
177 static pj_status_t stream_set_cap(pjmedia_aud_stream *strm,
178 				  pjmedia_aud_dev_cap cap,
179 				  const void *value);
180 static pj_status_t stream_start(pjmedia_aud_stream *strm);
181 static pj_status_t stream_stop(pjmedia_aud_stream *strm);
182 static pj_status_t stream_destroy(pjmedia_aud_stream *strm);
183 
184 /* End Prototypes */
185 
186 /* Operations */
187 static pjmedia_aud_dev_factory_op factory_op =
188 {
189     &factory_init,
190     &factory_destroy,
191     &factory_get_dev_count,
192     &factory_get_dev_info,
193     &factory_default_param,
194     &factory_create_stream,
195     &factory_refresh
196 };
197 
198 static pjmedia_aud_stream_op stream_op =
199 {
200     &stream_get_param,
201     &stream_get_cap,
202     &stream_set_cap,
203     &stream_start,
204     &stream_stop,
205     &stream_destroy
206 };
207 
208 /* End Operations */
209 
210 /* Utility functions */
211 
BD_IMAD_PJ_WCHARtoCHAR(wchar_t * orig)212 char* BD_IMAD_PJ_WCHARtoCHAR(wchar_t *orig)
213 {
214     size_t origsize = wcslen(orig)+1;
215     const size_t newsize = origsize*sizeof(wchar_t);
216     char *nstring = (char*)calloc(newsize, sizeof(char));
217     wcstombs(nstring, orig, newsize);
218     return nstring;
219 }
220 
221 #ifdef __cplusplus
222 extern "C" {
223 #endif
224 void manage_code(const unsigned char * pCode, unsigned char *pMsg1,
225 		 unsigned char * pMsg2);
226 #ifdef __cplusplus
227 }
228 #endif
229 
230 /* End Utility functions */
231 
232 /****************************************************************************
233 * Factory operations
234 */
235 
236 /* Init BDIMAD audio driver */
pjmedia_bdimad_factory(pj_pool_factory * pf)237 pjmedia_aud_dev_factory* pjmedia_bdimad_factory(pj_pool_factory *pf)
238 {
239     struct bd_factory *f;
240     pj_pool_t *pool;
241 
242     pool = pj_pool_create(pf, "BDIMAD_DRIVER", 1000, 1000, NULL);
243     f = PJ_POOL_ZALLOC_T(pool, struct bd_factory);
244     f->pf = pf;
245     f->base_pool = pool;
246     f->base.op = &factory_op;
247     f->pool = NULL;
248     f->dev_count = 0;
249     f->dev_info = NULL;
250 
251     return &f->base;
252 }
253 
254 /* API: init factory */
factory_init(pjmedia_aud_dev_factory * f)255 static pj_status_t factory_init(pjmedia_aud_dev_factory *f)
256 {
257     pj_status_t ret = factory_refresh(f);
258     if (ret != PJ_SUCCESS) return ret;
259 
260     PJ_LOG(4, (THIS_FILE, "BDIMAD initialized"));
261 
262     return PJ_SUCCESS;
263 }
264 
265 /* API: refresh the device list */
factory_refresh(pjmedia_aud_dev_factory * f)266 static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f)
267 {
268     struct bd_factory *wf = (struct bd_factory*)f;
269     unsigned int i = 0;
270     wchar_t *deviceNamep=NULL;
271     wchar_t captureDevName[BD_IMAD_MAX_DEV_COUNT][BD_IMAD_MAX_DEV_LENGTH_NAME];
272     unsigned int captureDeviceCount = 0;
273     wchar_t playbackDevName[BD_IMAD_MAX_DEV_COUNT][BD_IMAD_MAX_DEV_LENGTH_NAME];
274     unsigned int playbackDeviceCount = 0;
275 
276 
277     if(wf->pool != NULL) {
278         pj_pool_release(wf->pool);
279         wf->pool = NULL;
280     }
281 
282     // Enumerate capture sound devices
283     while(bdIMADpj_getDeviceName(BD_IMAD_CAPTURE_DEVICES, &deviceNamep) !=
284 	  BD_PJ_ERROR_IMAD_DEVICE_LIST_EMPTY)
285     {
286         wcscpy(captureDevName[captureDeviceCount], deviceNamep);
287         captureDeviceCount++;
288     }
289 
290     // Enumerate playback sound devices
291     while(bdIMADpj_getDeviceName(BD_IMAD_PLAYBACK_DEVICES, &deviceNamep) !=
292 	  BD_PJ_ERROR_IMAD_DEVICE_LIST_EMPTY)
293     {
294         wcscpy(playbackDevName[playbackDeviceCount], deviceNamep);
295         playbackDeviceCount++;
296     }
297 
298     // Set devices info
299     wf->dev_count = captureDeviceCount + playbackDeviceCount;
300     wf->pool = pj_pool_create(wf->pf, "BD_IMAD_DEVICES", 1000, 1000, NULL);
301     wf->dev_info = (struct bddev_info*)pj_pool_calloc(wf->pool, wf->dev_count,
302 						     sizeof(struct bddev_info));
303 
304     // Capture device properties
305     for(i=0;i<captureDeviceCount;i++) {
306         wf->dev_info[i].deviceId = i;
307 		bdIMADpj_getDeviceCapabilities(BD_IMAD_CAPTURE_DEVICES,&wf->dev_info[i].info.caps);
308         wf->dev_info[i].info.default_samples_per_sec = BD_IMAD_DEFAULT_FREQ;
309         strcpy(wf->dev_info[i].info.driver, "BD_IMAD");
310         wf->dev_info[i].info.ext_fmt_cnt = 0;
311         wf->dev_info[i].info.input_count = BD_IMAD_MAX_CHANNELS;
312         wf->dev_info[i].info.output_count = 0;
313         strcpy(wf->dev_info[i].info.name,
314 	       BD_IMAD_PJ_WCHARtoCHAR(captureDevName[i]));
315         wf->dev_info[i].info.routes = 0;
316     }
317 
318     // Playback device properties
319     for(i=0;i<playbackDeviceCount;i++) {
320         wf->dev_info[captureDeviceCount+i].deviceId = captureDeviceCount+i;
321 		bdIMADpj_getDeviceCapabilities(BD_IMAD_PLAYBACK_DEVICES,&wf->dev_info[captureDeviceCount+i].info.caps);
322         wf->dev_info[captureDeviceCount+i].info.default_samples_per_sec =
323 				BD_IMAD_DEFAULT_FREQ;
324         strcpy(wf->dev_info[captureDeviceCount+i].info.driver, "BD_IMAD");
325         wf->dev_info[captureDeviceCount+i].info.ext_fmt_cnt = 0;
326         wf->dev_info[captureDeviceCount+i].info.input_count = 0;
327         wf->dev_info[captureDeviceCount+i].info.output_count =
328 				BD_IMAD_MAX_CHANNELS;
329         strcpy(wf->dev_info[captureDeviceCount+i].info.name,
330 	       BD_IMAD_PJ_WCHARtoCHAR(playbackDevName[i]));
331         wf->dev_info[captureDeviceCount+i].info.routes = 0;
332     }
333 
334     PJ_LOG(4, (THIS_FILE, "BDIMAD found %d devices:", wf->dev_count));
335     for(i=0; i<wf->dev_count; i++) {
336         PJ_LOG(4,
337 	       (THIS_FILE, " dev_id %d: %s  (in=%d, out=%d)",
338                i,
339                wf->dev_info[i].info.name,
340                wf->dev_info[i].info.input_count,
341                wf->dev_info[i].info.output_count));
342     }
343     return PJ_SUCCESS;
344 }
345 
346 /* API: destroy factory */
factory_destroy(pjmedia_aud_dev_factory * f)347 static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f)
348 {
349     struct bd_factory *wf = (struct bd_factory*)f;
350     pj_pool_t *pool = wf->base_pool;
351 
352     pj_pool_release(wf->pool);
353     wf->base_pool = NULL;
354     pj_pool_release(pool);
355 
356     return PJ_SUCCESS;
357 }
358 
359 /* API: get number of devices */
factory_get_dev_count(pjmedia_aud_dev_factory * f)360 static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f)
361 {
362     struct bd_factory *wf = (struct bd_factory*)f;
363     return wf->dev_count;
364 }
365 
366 /* API: get device info */
factory_get_dev_info(pjmedia_aud_dev_factory * f,unsigned index,pjmedia_aud_dev_info * info)367 static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,
368                                         unsigned index,
369                                         pjmedia_aud_dev_info *info)
370 {
371     struct bd_factory *wf = (struct bd_factory*)f;
372 
373     PJ_ASSERT_RETURN(index < wf->dev_count, PJMEDIA_EAUD_INVDEV);
374 
375     pj_memcpy(info, &wf->dev_info[index].info, sizeof(*info));
376 
377     return PJ_SUCCESS;
378 }
379 
380 /* API: create default device parameter */
factory_default_param(pjmedia_aud_dev_factory * f,unsigned index,pjmedia_aud_param * param)381 static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
382                                          unsigned index,
383                                          pjmedia_aud_param *param)
384 {
385     struct bd_factory *wf = (struct bd_factory*)f;
386     struct bddev_info *di = &wf->dev_info[index];
387 
388     pj_bzero(param, sizeof(*param));
389     if (di->info.input_count && di->info.output_count) {
390         param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
391         param->rec_id = index;
392         param->play_id = index;
393         param->channel_count = di->info.output_count;
394     } else if(di->info.input_count) {
395         param->dir = PJMEDIA_DIR_CAPTURE;
396         param->rec_id = index;
397         param->play_id = PJMEDIA_AUD_INVALID_DEV;
398         param->channel_count = di->info.input_count;
399     } else if(di->info.output_count) {
400         param->dir = PJMEDIA_DIR_PLAYBACK;
401         param->play_id = index;
402         param->rec_id = PJMEDIA_AUD_INVALID_DEV;
403         param->channel_count = di->info.output_count;
404     } else {
405         return PJMEDIA_EAUD_INVDEV;
406     }
407 
408     param->bits_per_sample = BD_IMAD_BITS_X_SAMPLE;
409     param->clock_rate = di->info.default_samples_per_sec;
410     param->flags = di->info.caps;
411     param->samples_per_frame = di->info.default_samples_per_sec *
412 			       param->channel_count *
413 			       BD_IMAD_MSECOND_PER_BUFFER /
414 			       1000;
415 
416     if(di->info.caps & PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING) {
417         param->input_vol = BD_IMAD_STARTING_INPUT_VOLUME;
418     }
419 
420     if(di->info.caps & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
421         param->output_vol = BD_IMAD_STARTING_OUTPUT_VOLUME;
422     }
423 
424     if(di->info.caps & PJMEDIA_AUD_DEV_CAP_EC) {
425         param->ec_enabled = PJ_TRUE;
426     }
427 
428 	if(di->info.caps & PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE) {
429 		param->output_route = PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER;
430     }
431 
432     return PJ_SUCCESS;
433 }
434 
435 /* callbacks to set data */
bdimad_CaptureCallback(void * buffer,int samples,void * user_data)436 void bdimad_CaptureCallback(void *buffer, int samples, void *user_data)
437 {
438     pj_status_t status = PJ_SUCCESS;
439     pjmedia_frame frame;
440     unsigned nsamples;
441 
442     struct bd_stream *strm = (struct bd_stream*)user_data;
443 
444     if(!strm->go)
445 	goto on_break;
446 
447     /* Known cases of callback's thread:
448      * - The thread may be changed in the middle of a session, e.g: in MacOS
449      *   it happens when plugging/unplugging headphone.
450      * - The same thread may be reused in consecutive sessions. The first
451      *   session will leave TLS set, but release the TLS data address,
452      *   so the second session must re-register the callback's thread.
453      */
454     if (strm->rec_thread_initialized == 0 || !pj_thread_is_registered())
455     {
456 	pj_bzero(strm->rec_thread_desc, sizeof(pj_thread_desc));
457 	status = pj_thread_register("bd_CaptureCallback",
458 				    strm->rec_thread_desc,
459 				    &strm->rec_thread);
460 	if (status != PJ_SUCCESS)
461 	    goto on_break;
462 
463 	strm->rec_thread_initialized = 1;
464 	PJ_LOG(5,(THIS_FILE, "Recorder thread started"));
465     }
466 
467     /* Calculate number of samples we've got */
468     nsamples = samples * strm->channel_count + strm->rec_buf_count;
469 
470     /*
471     RECORD
472     */
473     if (strm->fmt_id == PJMEDIA_FORMAT_L16) {
474 	if (nsamples >= strm->samples_per_frame) {
475 	    /* If buffer is not empty, combine the buffer with the just incoming
476 	     * samples, then call put_frame.
477 	     */
478 	    if (strm->rec_buf_count) {
479 		unsigned chunk_count = 0;
480 
481 		chunk_count = strm->samples_per_frame - strm->rec_buf_count;
482 		pjmedia_copy_samples(strm->rec_buf + strm->rec_buf_count,
483 				     (pj_int16_t*)buffer, chunk_count);
484 
485 		frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
486 		frame.buf = (void*) strm->rec_buf;
487 		frame.size = strm->bytes_per_frame;
488 		frame.timestamp.u64 = strm->timestampCapture.u64;
489 		frame.bit_info = 0;
490 
491 		status = (*strm->rec_cb)(strm->user_data, &frame);
492 
493 		buffer = (pj_int16_t*) buffer + chunk_count;
494 		nsamples -= strm->samples_per_frame;
495 		strm->rec_buf_count = 0;
496 		strm->timestampCapture.u64 += strm->samples_per_frame /
497 					      strm->channel_count;
498 	    }
499 
500 	    /* Give all frames we have */
501 	    while (nsamples >= strm->samples_per_frame && status == 0) {
502 		frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
503 		frame.buf = (void*) buffer;
504 		frame.size = strm->bytes_per_frame;
505 		frame.timestamp.u64 = strm->timestampCapture.u64;
506 		frame.bit_info = 0;
507 
508 		status = (*strm->rec_cb)(strm->user_data, &frame);
509 
510 		buffer = (pj_int16_t*) buffer + strm->samples_per_frame;
511 		nsamples -= strm->samples_per_frame;
512 		strm->timestampCapture.u64 += strm->samples_per_frame /
513 					      strm->channel_count;
514 	    }
515 
516 	    /* Store the remaining samples into the buffer */
517 	    if (nsamples && status == 0) {
518 		strm->rec_buf_count = nsamples;
519 		pjmedia_copy_samples(strm->rec_buf, (pj_int16_t*)buffer,
520 				     nsamples);
521 	    }
522 
523 	} else {
524 	    /* Not enough samples, let's just store them in the buffer */
525 	    pjmedia_copy_samples(strm->rec_buf + strm->rec_buf_count,
526 				 (pj_int16_t*)buffer,
527 				 samples * strm->channel_count);
528 	    strm->rec_buf_count += samples * strm->channel_count;
529 	}
530     }  else {
531         pj_assert(!"Frame type not supported");
532     }
533 
534     strm->timestampCapture.u64 += strm->param.samples_per_frame /
535 				  strm->param.channel_count;
536 
537     if (status==0)
538 	return;
539 
540 on_break:
541     strm->rec_thread_exited = 1;
542 }
543 
544 /* callbacks to get data */
bdimad_PlaybackCallback(void * buffer,int samples,void * user_data)545 int bdimad_PlaybackCallback(void *buffer, int samples, void *user_data)
546 {
547     pj_status_t status = PJ_SUCCESS;
548     pjmedia_frame frame;
549     struct bd_stream *strm = (struct bd_stream*)user_data;
550     unsigned nsamples_req = samples * strm->channel_count;
551 
552     if(!strm->go)
553 	goto on_break;
554 
555     /* Known cases of callback's thread:
556      * - The thread may be changed in the middle of a session, e.g: in MacOS
557      *   it happens when plugging/unplugging headphone.
558      * - The same thread may be reused in consecutive sessions. The first
559      *   session will leave TLS set, but release the TLS data address,
560      *   so the second session must re-register the callback's thread.
561      */
562     if (strm->play_thread_initialized == 0 || !pj_thread_is_registered())
563     {
564 	pj_bzero(strm->play_thread_desc, sizeof(pj_thread_desc));
565 	status = pj_thread_register("bd_PlaybackCallback",
566 				    strm->play_thread_desc,
567 				    &strm->play_thread);
568 	if (status != PJ_SUCCESS)
569 	    goto on_break;
570 
571 	strm->play_thread_initialized = 1;
572 	PJ_LOG(5,(THIS_FILE, "Player thread started"));
573     }
574 
575     /*
576     PLAY
577     */
578     if(strm->fmt_id == PJMEDIA_FORMAT_L16) {
579 	/* Check if any buffered samples */
580 	if (strm->play_buf_count) {
581 	    /* samples buffered >= requested by sound device */
582 	    if (strm->play_buf_count >= nsamples_req) {
583 		pjmedia_copy_samples((pj_int16_t*)buffer, strm->play_buf,
584 				     nsamples_req);
585 		strm->play_buf_count -= nsamples_req;
586 		pjmedia_move_samples(strm->play_buf,
587 				     strm->play_buf + nsamples_req,
588 				     strm->play_buf_count);
589 
590 		return nsamples_req;
591 	    }
592 
593 	    /* samples buffered < requested by sound device */
594 	    pjmedia_copy_samples((pj_int16_t*)buffer, strm->play_buf,
595 				 strm->play_buf_count);
596 	    nsamples_req -= strm->play_buf_count;
597 	    buffer = (pj_int16_t*)buffer + strm->play_buf_count;
598 	    strm->play_buf_count = 0;
599 	}
600 
601 	/* Fill output buffer as requested */
602 	while (nsamples_req && status == 0) {
603 	    if (nsamples_req >= strm->samples_per_frame) {
604 		frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
605 		frame.buf = buffer;
606 		frame.size = strm->bytes_per_frame;
607 		frame.timestamp.u64 = strm->timestampPlayback.u64;
608 		frame.bit_info = 0;
609 
610 		status = (*strm->play_cb)(strm->user_data, &frame);
611 		if (status != PJ_SUCCESS)
612 		    return 0;
613 
614 		if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
615 		    pj_bzero(frame.buf, frame.size);
616 
617 		nsamples_req -= strm->samples_per_frame;
618 		buffer = (pj_int16_t*)buffer + strm->samples_per_frame;
619 	    } else {
620 		frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
621 		frame.buf = strm->play_buf;
622 		frame.size = strm->bytes_per_frame;
623 		frame.timestamp.u64 = strm->timestampPlayback.u64;
624 		frame.bit_info = 0;
625 
626 		status = (*strm->play_cb)(strm->user_data, &frame);
627 		if (status != PJ_SUCCESS)
628 		    return 0;
629 
630 		if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
631 		    pj_bzero(frame.buf, frame.size);
632 
633 		pjmedia_copy_samples((pj_int16_t*)buffer, strm->play_buf,
634 				     nsamples_req);
635 		strm->play_buf_count = strm->samples_per_frame -
636 				       nsamples_req;
637 		pjmedia_move_samples(strm->play_buf,
638 				     strm->play_buf+nsamples_req,
639 				     strm->play_buf_count);
640 		nsamples_req = 0;
641 	    }
642 
643 	    strm->timestampPlayback.u64 += strm->samples_per_frame /
644 					   strm->channel_count;
645 	}
646     } else {
647         pj_assert(!"Frame type not supported");
648     }
649 
650     if(status != PJ_SUCCESS) {
651         return 0;
652     }
653 
654     strm->timestampPlayback.u64 += strm->param.samples_per_frame /
655 				   strm->param.channel_count;
656 
657     if (status == 0)
658 	return samples;
659 
660 on_break:
661     strm->play_thread_exited = 1;
662     return 0;
663 }
664 
665 /* Internal: Get format name */
get_fmt_name(pj_uint32_t id)666 static const char *get_fmt_name(pj_uint32_t id)
667 {
668     static char name[8];
669 
670     if (id == PJMEDIA_FORMAT_L16)
671         return "PCM";
672     pj_memcpy(name, &id, 4);
673     name[4] = '\0';
674     return name;
675 }
676 
677 /* Internal: create BD device. */
init_streams(struct bd_factory * wf,struct bd_stream * strm,const pjmedia_aud_param * prm)678 static pj_status_t init_streams(struct bd_factory *wf,
679                                 struct bd_stream *strm,
680                                 const pjmedia_aud_param *prm)
681 {
682     unsigned ptime;
683     enum bdIMADpj_Status errorInitAEC;
684     wchar_t *deviceNamep=NULL;
685     wchar_t captureDevName[BD_IMAD_MAX_DEV_COUNT][BD_IMAD_MAX_DEV_LENGTH_NAME];
686     int captureDeviceCount = 0;
687     wchar_t playbackDevName[BD_IMAD_MAX_DEV_COUNT][BD_IMAD_MAX_DEV_LENGTH_NAME];
688     int playbackDeviceCount = 0;
689 
690     PJ_ASSERT_RETURN(prm->play_id < (int)wf->dev_count, PJ_EINVAL);
691     PJ_ASSERT_RETURN(prm->rec_id < (int)wf->dev_count, PJ_EINVAL);
692 
693     ptime = prm->samples_per_frame *
694 	    1000 /
695 	    (prm->clock_rate * prm->channel_count);
696     strm->bytes_per_frame = (prm->clock_rate *
697 			    ((prm->channel_count * prm->bits_per_sample) / 8)) *
698 			     ptime /
699 			     1000;
700     strm->timestampCapture.u64 = 0;
701     strm->timestampPlayback.u64 = 0;
702 
703     //BD_IMAD_PJ
704     bdIMADpj_CreateStructures(&strm->bdIMADpjSettingsPtr,
705 			      &strm->bdIMADpjWarningPtr);
706 
707     strm->bdIMADpjSettingsPtr->FrameSize_ms = ptime;
708     strm->bdIMADpjSettingsPtr->DiagnosticEnable = BD_IMAD_DIAGNOSTIC;
709     mbstowcs(bdImadPjDiagnosticFolderPath, BD_IMAD_DIAGNOSTIC_PATH, strlen(BD_IMAD_DIAGNOSTIC_PATH));
710     strm->bdIMADpjSettingsPtr->DiagnosticFolderPath = bdImadPjDiagnosticFolderPath;
711     strm->bdIMADpjSettingsPtr->validate = (void *)manage_code;
712 
713     if(prm->clock_rate != 8000 && prm->clock_rate != 16000
714 	   && prm->clock_rate != 32000 && prm->clock_rate != 44100 && prm->clock_rate != 48000) {
715         PJ_LOG(4, (THIS_FILE,
716 		   "BDIMAD support 8000 Hz, 16000 Hz, 32000 Hz, 44100 Hz and 48000 Hz "
717 		   "frequency."));
718     }
719     strm->bdIMADpjSettingsPtr->SamplingFrequency = prm->clock_rate;
720 
721     if(prm->channel_count > BD_IMAD_MAX_CHANNELS) {
722         PJ_LOG(4, (THIS_FILE,
723 		   "BDIMAD doesn't support a number of channels upper than %d.",
724 		   BD_IMAD_MAX_CHANNELS));
725     }
726 
727     // Enumerate capture sound devices
728     while(bdIMADpj_getDeviceName(BD_IMAD_CAPTURE_DEVICES, &deviceNamep) !=
729 	  BD_PJ_ERROR_IMAD_DEVICE_LIST_EMPTY)
730     {
731         wcscpy(captureDevName[captureDeviceCount], deviceNamep);
732         captureDeviceCount++;
733     }
734     strm->bdIMADpjSettingsPtr->CaptureDevice = captureDevName[(int)prm->rec_id];
735 
736     // Enumerate playback sound devices
737     while(bdIMADpj_getDeviceName(BD_IMAD_PLAYBACK_DEVICES, &deviceNamep) !=
738 	  BD_PJ_ERROR_IMAD_DEVICE_LIST_EMPTY)
739     {
740         wcscpy(playbackDevName[playbackDeviceCount], deviceNamep);
741         playbackDeviceCount++;
742     }
743     strm->bdIMADpjSettingsPtr->PlayDevice =
744 		    playbackDevName[(int)(prm->play_id-captureDeviceCount)];
745 
746     strm->bdIMADpjSettingsPtr->cb_emptyCaptureBuffer = &bdimad_CaptureCallback;
747     strm->bdIMADpjSettingsPtr->cb_emptyCaptureBuffer_user_data = (void*)strm;
748     strm->bdIMADpjSettingsPtr->cb_fillPlayBackBuffer = &bdimad_PlaybackCallback;
749     strm->bdIMADpjSettingsPtr->cb_fillPlayBackBuffer_user_data = (void*)strm;
750 
751     if(strm->bdIMADpjInstance != NULL)
752         bdIMADpj_FreeAEC(&strm->bdIMADpjInstance);
753     strm->bdIMADpjInstance = NULL;
754 
755     errorInitAEC = bdIMADpj_InitAEC(&strm->bdIMADpjInstance,
756 				    &strm->bdIMADpjSettingsPtr,
757 				    &strm->bdIMADpjWarningPtr);
758 
759     {
760 	int auxInt = (prm->ec_enabled == PJ_TRUE ? 1 : 0);
761         bdIMADpj_setParameter(strm->bdIMADpjInstance,
762 			      BD_PARAM_IMAD_PJ_AEC_ENABLE,
763 			      &auxInt);
764         auxInt = 1;
765         //Mic control On by default
766         bdIMADpj_setParameter(strm->bdIMADpjInstance,
767 			      BD_PARAM_IMAD_PJ_MIC_CONTROL_ENABLE,
768 			      &auxInt);
769 
770 		// Enable GUI Socket Communication [default->disabled]
771 		bdIMADpj_enableGuiSocketCommunication(strm->bdIMADpjInstance,27000,0);
772     }
773 
774     if(errorInitAEC != BD_PJ_OK &&
775        errorInitAEC != BD_PJ_WARN_BDIMAD_WARNING_ASSERTED)
776     {
777         return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(errorInitAEC);
778     }
779 
780     return PJ_SUCCESS;
781 }
782 
783 /****************************************
784             API: create stream
785 *****************************************/
stream_stopBDIMAD(pjmedia_aud_stream * s)786 static pj_status_t stream_stopBDIMAD(pjmedia_aud_stream *s)
787 {
788     struct bd_stream *strm = (struct bd_stream*)s;
789     pj_status_t status = PJ_SUCCESS;
790     int i, err = 0;
791 
792     PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
793 
794     strm->go = 0;
795 
796     for (i=0; !strm->rec_thread_exited && i<100; ++i)
797 	pj_thread_sleep(10);
798     for (i=0; !strm->play_thread_exited && i<100; ++i)
799 	pj_thread_sleep(10);
800 
801     pj_thread_sleep(1);
802 
803     PJ_LOG(5,(THIS_FILE, "Stopping stream.."));
804 
805     strm->play_thread_initialized = 0;
806     strm->rec_thread_initialized = 0;
807 
808     PJ_LOG(5,(THIS_FILE, "Done, status=%d", err));
809 
810     return status;
811 }
812 
stream_stop(pjmedia_aud_stream * s)813 static pj_status_t stream_stop(pjmedia_aud_stream *s)
814 {
815     struct bd_stream *strm = (struct bd_stream*)s;
816 
817     PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
818 
819     if(strm->bdIMADpjInstance != NULL) {
820         return stream_stopBDIMAD(s);
821     } else {
822         return PJMEDIA_EAUD_ERR;
823     }
824 }
825 
stream_destroyBDIMAD(pjmedia_aud_stream * s)826 static pj_status_t stream_destroyBDIMAD(pjmedia_aud_stream *s)
827 {
828     struct bd_stream *strm = (struct bd_stream*)s;
829     int i = 0;
830 
831     PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
832 
833     stream_stopBDIMAD(s);
834 
835     // DeInit BDIMAD
836     bdIMADpj_FreeAEC(&strm->bdIMADpjInstance);
837 	PJ_LOG(4, (THIS_FILE, "Free AEC"));
838 
839     bdIMADpj_FreeStructures(&strm->bdIMADpjSettingsPtr,
840 			    &strm->bdIMADpjWarningPtr);
841     PJ_LOG(4, (THIS_FILE, "Free AEC Structure"));
842 
843     strm->bdIMADpjInstance = NULL;
844     strm->bdIMADpjSettingsPtr = NULL;
845     strm->bdIMADpjWarningPtr = NULL;
846 
847     strm->quit_flag = 1;
848     for (i=0; !strm->rec_thread_exited && i<100; ++i) {
849 	pj_thread_sleep(1);
850     }
851     for (i=0; !strm->play_thread_exited && i<100; ++i) {
852 	pj_thread_sleep(1);
853     }
854 
855     PJ_LOG(5,(THIS_FILE, "Destroying stream.."));
856 
857     pj_pool_release(strm->pool);
858     return PJ_SUCCESS;
859 }
860 
861 /* API: Destroy stream. */
stream_destroy(pjmedia_aud_stream * s)862 static pj_status_t stream_destroy(pjmedia_aud_stream *s)
863 {
864     struct bd_stream *strm = (struct bd_stream*)s;
865 
866     PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
867 
868     if(strm->bdIMADpjInstance != NULL) {
869         return stream_destroyBDIMAD(s);
870     } else {
871         return PJMEDIA_EAUD_ERR;
872     }
873 }
874 
875 /* API: set capability */
stream_set_capBDIMAD(pjmedia_aud_stream * s,pjmedia_aud_dev_cap cap,const void * pval)876 static pj_status_t stream_set_capBDIMAD(pjmedia_aud_stream *s,
877 					pjmedia_aud_dev_cap cap,
878 					const void *pval)
879 {
880     struct bd_stream *strm = (struct bd_stream*)s;
881     bdIMADpj_Status res = BD_PJ_OK;
882     PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
883 
884     if(cap == PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
885         /* Output volume setting */
886         float vol = (float)*(unsigned*)pval;
887 
888         if(vol > 100.0f) vol = 100.0f;
889         if(vol < 0.0f) vol = 0.0f;
890 
891         vol = vol / 100.0f;
892         res = bdIMADpj_setParameter(strm->bdIMADpjInstance,
893 				    BD_PARAM_IMAD_PJ_SPK_VOLUME, &vol);
894 
895 
896         if(res == BD_PJ_OK) {
897             strm->param.output_vol = *(unsigned*)pval;
898             return PJ_SUCCESS;
899         } else {
900             return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(res);
901         }
902     }
903 
904     if(cap == PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING) {
905         /* Input volume setting */
906         float vol = (float)*(unsigned*)pval;
907 
908         if(vol > 100.0f) vol = 100.0f;
909         if(vol < 0.0f) vol = 0.0f;
910 
911         vol = vol / 100.0f;
912         res = bdIMADpj_setParameter(strm->bdIMADpjInstance,
913 				    BD_PARAM_IMAD_PJ_MIC_VOLUME, &vol);
914         if(res == BD_PJ_OK) {
915             strm->param.input_vol = *(unsigned*)pval;
916             return PJ_SUCCESS;
917         } else {
918             return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(res);
919         }
920     }
921 
922     if(cap == PJMEDIA_AUD_DEV_CAP_EC) {
923         int aecOnOff = (*(pj_bool_t*)pval == PJ_TRUE ? 1 : 0);
924 
925         /* AEC setting */
926         res = bdIMADpj_setParameter(strm->bdIMADpjInstance,
927 				    BD_PARAM_IMAD_PJ_AEC_ENABLE,
928 				    &aecOnOff);
929         if(res == BD_PJ_OK) {
930             strm->param.ec_enabled = (aecOnOff == 1 ? PJ_TRUE : PJ_FALSE);
931             return PJ_SUCCESS;
932         } else {
933             return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(res);
934         }
935     }
936 
937 	if(cap == PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE) {
938 		pjmedia_aud_dev_route outputRoute = *(pjmedia_aud_dev_route*)pval;
939 		res = bdIMADpj_setRouteOutputDevice(strm->bdIMADpjInstance, (bdIMADpj_out_dev_route) outputRoute, &strm->bdIMADpjWarningPtr);
940 		if(res == BD_PJ_OK) {
941 			strm->param.output_route = outputRoute;
942             return PJ_SUCCESS;
943         } else {
944             return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(res);
945         }
946 	}
947 
948     return PJMEDIA_EAUD_INVCAP;
949 }
950 
factory_create_streamBDIMAD(pjmedia_aud_dev_factory * f,const pjmedia_aud_param * param,pjmedia_aud_rec_cb rec_cb,pjmedia_aud_play_cb play_cb,void * user_data,pjmedia_aud_stream ** p_aud_strm)951 static pj_status_t factory_create_streamBDIMAD(pjmedia_aud_dev_factory *f,
952                                     const pjmedia_aud_param *param,
953                                     pjmedia_aud_rec_cb rec_cb,
954                                     pjmedia_aud_play_cb play_cb,
955                                     void *user_data,
956                                     pjmedia_aud_stream **p_aud_strm)
957 {
958     struct bd_factory *wf = (struct bd_factory*)f;
959     pj_pool_t *pool;
960     struct bd_stream *strm;
961     pj_uint8_t silence_char;
962     pj_status_t status;
963 
964     switch (param->ext_fmt.id) {
965     case PJMEDIA_FORMAT_L16:
966 	silence_char = '\0';
967 	break;
968     default:
969 	return PJMEDIA_EAUD_BADFORMAT;
970     }
971 
972     /* Create and Initialize stream descriptor */
973     pool = pj_pool_create(wf->pf, "BDIMAD_STREAM", 1000, 1000, NULL);
974     PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
975 
976     strm = PJ_POOL_ZALLOC_T(pool, struct bd_stream);
977     pj_memcpy(&strm->param, param, sizeof(*param));
978     strm->pool = pool;
979     strm->rec_cb = rec_cb;
980     strm->play_cb = play_cb;
981     strm->user_data = user_data;
982     strm->fmt_id = (pjmedia_format_id)param->ext_fmt.id;
983     strm->silence_char = silence_char;
984     strm->channel_count = param->channel_count;
985     strm->samples_per_frame = param->samples_per_frame;
986 
987     if (param->dir & PJMEDIA_DIR_CAPTURE_PLAYBACK) {
988         status = init_streams(wf, strm, param);
989 
990         if (status != PJ_SUCCESS) {
991             stream_destroyBDIMAD(&strm->base);
992             return status;
993         }
994     } else {
995         stream_destroyBDIMAD(&strm->base);
996         return PJMEDIA_EAUD_ERR;
997     }
998 
999     strm->rec_buf = (pj_int16_t*)pj_pool_alloc(pool,
1000 		    strm->bytes_per_frame);
1001     if (!strm->rec_buf) {
1002         pj_pool_release(pool);
1003         return PJ_ENOMEM;
1004     }
1005     strm->rec_buf_count = 0;
1006 
1007     strm->play_buf = (pj_int16_t*)pj_pool_alloc(pool,
1008 		     strm->bytes_per_frame);
1009     if (!strm->play_buf) {
1010         pj_pool_release(pool);
1011         return PJ_ENOMEM;
1012     }
1013     strm->play_buf_count = 0;
1014 
1015     /* Apply the remaining settings */
1016     if(param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
1017         stream_set_capBDIMAD(&strm->base,
1018 			     PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
1019 			     &param->output_vol);
1020     }
1021     if(param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING) {
1022         stream_set_capBDIMAD(&strm->base,
1023 			     PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING,
1024 			     &param->input_vol);
1025     }
1026     if(param->flags & PJMEDIA_AUD_DEV_CAP_EC) {
1027         stream_set_capBDIMAD(&strm->base,
1028 			     PJMEDIA_AUD_DEV_CAP_EC,
1029 			     &param->ec_enabled);
1030     }
1031 
1032     if(param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE) {
1033 		stream_set_capBDIMAD(&strm->base,
1034 				PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE,
1035 				 &param->output_route);
1036 	}
1037 
1038     strm->base.op = &stream_op;
1039     *p_aud_strm = &strm->base;
1040 
1041     return PJ_SUCCESS;
1042 }
1043 
factory_create_stream(pjmedia_aud_dev_factory * f,const pjmedia_aud_param * param,pjmedia_aud_rec_cb rec_cb,pjmedia_aud_play_cb play_cb,void * user_data,pjmedia_aud_stream ** p_aud_strm)1044 static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
1045 					 const pjmedia_aud_param *param,
1046 					 pjmedia_aud_rec_cb rec_cb,
1047 					 pjmedia_aud_play_cb play_cb,
1048 					 void *user_data,
1049 					 pjmedia_aud_stream **p_aud_strm)
1050 {
1051     return factory_create_streamBDIMAD(f, param, rec_cb,
1052 				       play_cb, user_data, p_aud_strm);
1053 }
1054 // ----------------------------------------------------------------------
1055 // ----------------------------------------------------------------------
1056 // ----------------------------------------------------------------------
1057 
1058 /* API: Get stream info. */
stream_get_param(pjmedia_aud_stream * s,pjmedia_aud_param * pi)1059 static pj_status_t stream_get_param(pjmedia_aud_stream *s,
1060                                     pjmedia_aud_param *pi)
1061 {
1062     struct bd_stream *strm = (struct bd_stream*)s;
1063 
1064     PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
1065 
1066     pj_memcpy(pi, &strm->param, sizeof(*pi));
1067 
1068     // Get the output volume setting
1069     if(stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
1070 		      &pi->output_vol) == PJ_SUCCESS)
1071     {
1072         pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
1073     }
1074 
1075     // Get the input volume setting
1076     if(stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING,
1077 		      &pi->input_vol) == PJ_SUCCESS)
1078     {
1079         pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING;
1080     }
1081 
1082     // Get the AEC setting
1083     if(stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_EC, &pi->ec_enabled) == PJ_SUCCESS)
1084     {
1085         pi->flags |= PJMEDIA_AUD_DEV_CAP_EC;
1086     }
1087 	if(stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_EC, &pi->ec_enabled) == PJ_SUCCESS)
1088     {
1089         pi->flags |= PJMEDIA_AUD_DEV_CAP_EC;
1090     }
1091 
1092 
1093     // Get the Route Output Device setting
1094     if(stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE, &pi->output_route) == PJ_SUCCESS)
1095     {
1096         pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE;
1097     }
1098 
1099     return PJ_SUCCESS;
1100 }
1101 
stream_get_capBDIMAD(pjmedia_aud_stream * s,pjmedia_aud_dev_cap cap,void * pval)1102 static pj_status_t stream_get_capBDIMAD(pjmedia_aud_stream *s,
1103                                         pjmedia_aud_dev_cap cap,
1104                                         void *pval)
1105 {
1106     struct bd_stream *strm = (struct bd_stream*)s;
1107     bdIMADpj_Status res = BD_PJ_OK;
1108 
1109     PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
1110 
1111     if(cap == PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING)
1112     {
1113         /* Input volume setting */
1114         float vol;
1115         res = bdIMADpj_getParameter(strm->bdIMADpjInstance,
1116 				    BD_PARAM_IMAD_PJ_MIC_VOLUME, &vol);
1117         if(res == BD_PJ_OK) {
1118 	    vol = vol * 100;
1119 	    if(vol > 100.0f) vol = 100.0f;
1120 	    if(vol < 0.0f) vol = 0.0f;
1121 	    *(unsigned int *)pval = (unsigned int)vol;
1122 	    return PJ_SUCCESS;
1123         } else{
1124             return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(res);
1125         }
1126     } else if(cap == PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
1127         /* Output volume setting */
1128         float vol;
1129         res = bdIMADpj_getParameter(strm->bdIMADpjInstance,
1130 				    BD_PARAM_IMAD_PJ_SPK_VOLUME, &vol);
1131         if(res == BD_PJ_OK) {
1132 			vol = vol * 100;
1133             if(vol > 100.0f) vol = 100.0f;
1134             if(vol < 0.0f) vol = 0.0f;
1135             *(unsigned int *)pval = (unsigned int)vol;
1136             return PJ_SUCCESS;
1137         } else {
1138             return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(res);
1139         }
1140     }
1141     else if(cap == PJMEDIA_AUD_DEV_CAP_EC) {
1142         int aecIsOn;
1143         res = bdIMADpj_getParameter(strm->bdIMADpjInstance,
1144 				    BD_PARAM_IMAD_PJ_AEC_ENABLE, &aecIsOn);
1145         if(res == BD_PJ_OK) {
1146             *(pj_bool_t*)pval = (aecIsOn == 1 ? PJ_TRUE : PJ_FALSE);
1147             return PJ_SUCCESS;
1148         } else {
1149             return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(res);
1150         }
1151     }
1152     else if(cap == PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE) {
1153     		pjmedia_aud_dev_route routeOutDev;
1154     		res = bdIMADpj_getRouteOutputDevice(strm->bdIMADpjInstance,(bdIMADpj_out_dev_route*)&routeOutDev);
1155             if(res == BD_PJ_OK) {
1156                 *(pjmedia_aud_dev_route*)pval = routeOutDev;
1157                 return PJ_SUCCESS;
1158             } else {
1159                 return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(res);
1160             }
1161     } else {
1162         return PJMEDIA_EAUD_INVCAP;
1163     }
1164 }
1165 
stream_startBDIMAD(pjmedia_aud_stream * s)1166 static pj_status_t stream_startBDIMAD(pjmedia_aud_stream *s)
1167 {
1168     struct bd_stream *strm = (struct bd_stream*)s;
1169 
1170     PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
1171 
1172     strm->go = 1;
1173 
1174     return PJ_SUCCESS;
1175 }
1176 
1177 /* API: get capability */
stream_get_cap(pjmedia_aud_stream * s,pjmedia_aud_dev_cap cap,void * pval)1178 static pj_status_t stream_get_cap(pjmedia_aud_stream *s,
1179                                   pjmedia_aud_dev_cap cap,
1180                                   void *pval)
1181 {
1182     struct bd_stream *strm = (struct bd_stream*)s;
1183 
1184     PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
1185 
1186     if(strm->bdIMADpjInstance != NULL) {
1187         return stream_get_capBDIMAD(s, cap, pval);
1188     } else {
1189         return PJMEDIA_EAUD_ERR;
1190     }
1191 }
1192 
1193 /* API: set capability */
stream_set_cap(pjmedia_aud_stream * s,pjmedia_aud_dev_cap cap,const void * pval)1194 static pj_status_t stream_set_cap(pjmedia_aud_stream *s,
1195                                   pjmedia_aud_dev_cap cap,
1196                                   const void *pval)
1197 {
1198     struct bd_stream *strm = (struct bd_stream*)s;
1199 
1200     PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
1201 
1202     if(strm->bdIMADpjInstance != NULL) {
1203         return stream_set_capBDIMAD(s, cap, pval);
1204     } else {
1205         return PJMEDIA_EAUD_ERR;
1206     }
1207 }
1208 
1209 /* API: Start stream. */
stream_start(pjmedia_aud_stream * s)1210 static pj_status_t stream_start(pjmedia_aud_stream *s)
1211 {
1212     struct bd_stream *strm = (struct bd_stream*)s;
1213 
1214     PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
1215 
1216     if(strm->bdIMADpjInstance != NULL) {
1217         return stream_startBDIMAD(s);
1218     } else {
1219         return PJMEDIA_EAUD_ERR;
1220     }
1221 }
1222 
1223 #if defined (_MSC_VER)
1224 #pragma comment ( lib, "bdClientValidation.lib" )
1225 #pragma comment ( lib, "bdIMADpj.lib" )
1226 #endif
1227 
1228 
1229 #endif    /* PJMEDIA_AUDIO_DEV_HAS_BDIMAD */
1230 
1231