audiomicspk.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. #include "precompile.h"
  2. #include "audiomicspk.h"
  3. #include "audiocontext.h"
  4. #include "audiolog.h"
  5. #include "./other/delaybuf.h"
  6. #include <portaudio.h>
  7. #include <assert.h>
  8. #define MAX_DELAY 60
  9. static int get_device_index(int indev, const char *key)
  10. {
  11. int i;
  12. int n = Pa_GetDeviceCount();
  13. for (i = 0; i < n; ++i) {
  14. const PaDeviceInfo* pInfo = Pa_GetDeviceInfo(i);
  15. if (indev) {
  16. if (pInfo->maxInputChannels && strstr(pInfo->name, key))
  17. return i;
  18. } else {
  19. if (pInfo->maxOutputChannels && strstr(pInfo->name, key))
  20. return i;
  21. }
  22. }
  23. return -1;
  24. }
  25. static int StreamCallback(const void *input,
  26. void *output,
  27. unsigned long frameCount,
  28. const PaStreamCallbackTimeInfo* timeInfo,
  29. PaStreamCallbackFlags statusFlags,
  30. void *userData)
  31. {
  32. audiomicspk_t *micspk = userData;
  33. apr_status_t status;
  34. if (micspk->opt & AMS_OPT_AS_ENGINE) {
  35. audiostream_t *stream;
  36. EnterCriticalSection(&micspk->engine_lock);
  37. stream = micspk->engine_downstream;
  38. if (stream) {
  39. if (input && audiostream_get_direction(stream)&STREAM_DIR_WRITE) {
  40. audioframe_t frm = {(void*)input, frameCount<<1, 0};
  41. stream->vtbl->write_frame(stream, &frm);
  42. }
  43. if (output && audiostream_get_direction(stream)&STREAM_DIR_READ) {
  44. audioframe_t frm = {output, frameCount<<1, 0};
  45. status = stream->vtbl->read_frame(stream, &frm);
  46. if (status != APR_SUCCESS || frm.size != frameCount<<1) {
  47. memset(output, 0, frameCount<<1);
  48. }
  49. }
  50. }
  51. LeaveCriticalSection(&micspk->engine_lock);
  52. } else {
  53. if (input) {
  54. if (micspk->rec_buf_cnt == 0 && frameCount == micspk->frame_samples) {
  55. delay_buf_put(micspk->rec_dbuf, (short*)input);
  56. } else {
  57. unsigned long nsamples = frameCount + micspk->rec_buf_cnt;
  58. while (nsamples >= micspk->frame_samples) {
  59. unsigned chunk_count = micspk->frame_samples - micspk->rec_buf_cnt;
  60. memcpy(micspk->rec_buf+micspk->rec_buf_cnt, input, chunk_count<<1);
  61. input = (const short*)input + chunk_count;
  62. delay_buf_put(micspk->rec_dbuf, micspk->rec_buf);
  63. micspk->rec_buf_cnt = 0;
  64. nsamples -= micspk->frame_samples;
  65. }
  66. if (nsamples > 0) {
  67. memcpy(micspk->rec_buf+micspk->rec_buf_cnt, input, nsamples<<1);
  68. micspk->rec_buf_cnt += nsamples;
  69. }
  70. }
  71. }
  72. if (output) {
  73. unsigned nsamples_req = frameCount;
  74. if (micspk->ply_buf_cnt == 0 && nsamples_req == micspk->frame_samples) {
  75. delay_buf_get(micspk->ply_dbuf, (short*)output);
  76. } else {
  77. if (micspk->ply_buf_cnt > 0) {
  78. memcpy(output, micspk->ply_buf, micspk->ply_buf_cnt<<1);
  79. output = (short*)output + micspk->ply_buf_cnt;
  80. micspk->ply_buf_cnt = 0;
  81. nsamples_req -= micspk->ply_buf_cnt;
  82. }
  83. while (nsamples_req > 0) {
  84. if (nsamples_req >= micspk->frame_samples) {
  85. delay_buf_get(micspk->ply_dbuf, (short*)output);
  86. output = (short*)output + micspk->frame_samples;
  87. nsamples_req -= micspk->frame_samples;
  88. } else {
  89. delay_buf_get(micspk->ply_dbuf, micspk->ply_buf);
  90. micspk->ply_buf_cnt = micspk->frame_samples;
  91. memcpy(output, micspk->ply_buf, nsamples_req<<1);
  92. output = (short*)output + nsamples_req;
  93. memmove(micspk->ply_buf, micspk->ply_buf+nsamples_req, (micspk->frame_samples-nsamples_req)<<1);
  94. nsamples_req = 0;
  95. }
  96. }
  97. }
  98. }
  99. }
  100. return paContinue;
  101. }
  102. static apr_status_t read_frame(void *self, audioframe_t *frame)
  103. {
  104. audiomicspk_t *micspk = CONTAINING_RECORD(self, audiomicspk_t, base);
  105. frame->size = 2*micspk->frame_samples;
  106. frame->dtmf = 0;
  107. delay_buf_get(micspk->rec_dbuf, (short*)frame->buffer);
  108. return APR_SUCCESS;
  109. }
  110. static apr_status_t write_frame(void *self, const audioframe_t *frame)
  111. {
  112. audiomicspk_t *micspk = CONTAINING_RECORD(self, audiomicspk_t, base);
  113. assert(micspk->frame_samples*2 == frame->size);
  114. delay_buf_put(micspk->ply_dbuf, (short*)frame->buffer);
  115. return APR_SUCCESS;
  116. }
  117. static audiostream_vtbl_t g_stream_vtbl = {
  118. &read_frame,
  119. &write_frame,
  120. };
  121. apr_status_t audiomicspk_create(apr_pool_t *pool,
  122. audioengine_t *engine,
  123. int opt,
  124. int clock,
  125. const char *rec_dev_key,
  126. const char *ply_dev_key,
  127. audiomicspk_t **p_micspk)
  128. {
  129. int rec_dev_id = -1;
  130. int ply_dev_id = -1;
  131. audiomicspk_t *micspk;
  132. PaStreamParameters outParam;
  133. PaStreamParameters inParam;
  134. PaStream *pa_stream;
  135. unsigned long frame_samples;
  136. PaError paError;
  137. if (opt == 0) {
  138. AUDIO_LOG_ERROR("audiomicspk create error, opt cannot be zero");
  139. return APR_BADARG;
  140. }
  141. frame_samples = FRAME_TIME * clock / 1000;
  142. if (opt & AMS_OPT_PLAY) {
  143. if (ply_dev_key) {
  144. int id = get_device_index(0, ply_dev_key);
  145. if (id == -1) {
  146. AUDIO_LOG_ERROR("invalid play dev name!");
  147. return APR_BADARG;
  148. }
  149. ply_dev_id = id;
  150. }
  151. }
  152. if (opt & AMS_OPT_RECORD) {
  153. if (rec_dev_key) {
  154. int id = get_device_index(1, rec_dev_key);
  155. if (id == -1) {
  156. AUDIO_LOG_ERROR("invalid record dev name!");
  157. return APR_BADARG;
  158. }
  159. rec_dev_id = id;
  160. }
  161. }
  162. if (opt & AMS_OPT_PLAY) {
  163. const PaDeviceInfo *info;
  164. if (ply_dev_id == -1) {
  165. ply_dev_id = Pa_GetDefaultOutputDevice();
  166. if (ply_dev_id == paNoDevice) {
  167. AUDIO_LOG_ERROR("audiomicspk create error, cannot find output device");
  168. return -1;
  169. }
  170. }
  171. info = Pa_GetDeviceInfo(ply_dev_id);
  172. outParam.device = ply_dev_id;
  173. outParam.channelCount = 1;
  174. outParam.sampleFormat = paInt16;
  175. outParam.suggestedLatency = info->defaultLowOutputLatency;
  176. outParam.hostApiSpecificStreamInfo = NULL;
  177. if (Pa_IsFormatSupported(NULL, &outParam, clock) != paNoError) {
  178. AUDIO_LOG_ERROR("audiomicspk create error, cannot open audio output device");
  179. return -1;
  180. }
  181. AUDIO_LOG_ERROR("audio out suggestedLatency:%f, in:%f", info->defaultLowOutputLatency, info->defaultLowInputLatency);
  182. }
  183. if (opt & AMS_OPT_RECORD) {
  184. const PaDeviceInfo *info;
  185. if (rec_dev_id == -1) {
  186. rec_dev_id = Pa_GetDefaultInputDevice();
  187. if (rec_dev_id == paNoDevice) {
  188. AUDIO_LOG_ERROR("audiomicspk create error, cannot find input device");
  189. return -1;
  190. }
  191. }
  192. info = Pa_GetDeviceInfo(rec_dev_id);
  193. inParam.device = rec_dev_id;
  194. inParam.channelCount = 1;
  195. inParam.sampleFormat = paInt16;
  196. inParam.suggestedLatency = info->defaultLowInputLatency;
  197. inParam.hostApiSpecificStreamInfo = NULL;
  198. if (Pa_IsFormatSupported(&inParam, NULL, clock) != paNoError) {
  199. AUDIO_LOG_ERROR("audiomicspk create error, cannot open audio input device");
  200. return -1;
  201. }
  202. AUDIO_LOG_ERROR("audio in suggestedLatency:%f, out:%f", info->defaultLowInputLatency, info->defaultLowOutputLatency);;
  203. }
  204. micspk = apr_palloc(pool, sizeof(audiomicspk_t));
  205. memset(micspk, 0, sizeof(audiomicspk_t));
  206. paError = Pa_OpenStream(&pa_stream,
  207. (opt & AMS_OPT_RECORD) ? &inParam : NULL,
  208. (opt & AMS_OPT_PLAY) ? &outParam : NULL,
  209. clock, frame_samples,
  210. paClipOff,
  211. &StreamCallback,
  212. micspk);
  213. if (paError != 0) {
  214. AUDIO_LOG_ERROR("audiomicspk create error, Pa_OpenStream function failed in dir! ");
  215. return APR_EGENERAL;
  216. }
  217. audiostream_init(engine, &g_stream_vtbl, &micspk->base);
  218. micspk->base.direction = 0;
  219. if (opt & AMS_OPT_PLAY) {
  220. delay_buf_create(clock, frame_samples, 1, MAX_DELAY, 0, (delay_buf**)&micspk->ply_dbuf);
  221. micspk->base.direction |= STREAM_DIR_WRITE;
  222. micspk->ply_buf = (short*)apr_palloc(pool, frame_samples<<1);
  223. micspk->ply_buf_cnt = 0;
  224. }
  225. if (opt & AMS_OPT_RECORD) {
  226. micspk->base.direction |= STREAM_DIR_READ;
  227. delay_buf_create(clock, frame_samples, 1, MAX_DELAY, 0, (delay_buf**)&micspk->rec_dbuf);
  228. micspk->rec_buf = (short*)apr_palloc(pool, frame_samples<<1);
  229. micspk->rec_buf_cnt = 0;
  230. }
  231. if (opt & AMS_OPT_AS_ENGINE)
  232. InitializeCriticalSection(&micspk->engine_lock);
  233. micspk->clock = clock;
  234. micspk->opt = opt;
  235. micspk->frame_samples = frame_samples;
  236. micspk->rec_dev_id = rec_dev_id;
  237. micspk->ply_dev_id = ply_dev_id;
  238. micspk->stream = pa_stream;
  239. paError = Pa_StartStream(pa_stream);
  240. if (paError != 0) {
  241. AUDIO_LOG_ERROR("audiomicspk create error, Pa_StartStream function failed in dir! ");
  242. Pa_CloseStream(pa_stream);
  243. micspk->stream = NULL;
  244. audiomicspk_destroy(micspk);
  245. return APR_EGENERAL;
  246. }
  247. *p_micspk = micspk;
  248. return APR_SUCCESS;
  249. }
  250. void audiomicspk_destroy(audiomicspk_t *micspk)
  251. {
  252. if (micspk->stream) {
  253. Pa_AbortStream(micspk->stream);
  254. Pa_CloseStream(micspk->stream);
  255. }
  256. if (micspk->ply_dbuf)
  257. delay_buf_destroy(micspk->ply_dbuf);
  258. if (micspk->rec_dbuf)
  259. delay_buf_destroy(micspk->rec_dbuf);
  260. if (micspk->opt & AMS_OPT_AS_ENGINE)
  261. DeleteCriticalSection(&micspk->engine_lock);
  262. }
  263. apr_status_t audiomicspk_connect_pipeline(audiomicspk_t *micspk, int direction, ...)
  264. {
  265. va_list arg;
  266. audiostream_t *p, *q;
  267. if (micspk->opt & AMS_OPT_AS_ENGINE)
  268. EnterCriticalSection(&micspk->engine_lock);
  269. va_start(arg, direction);
  270. for (q = NULL, p = va_arg(arg, audiostream_t*); p; q = p, p = va_arg(arg, audiostream_t*)) {
  271. if (q == NULL) {
  272. micspk->engine_downstream = p;
  273. } else {
  274. q->downstream = p;
  275. }
  276. p->direction = direction;
  277. p->upstream = q;
  278. }
  279. if (q)
  280. q->downstream = NULL;
  281. va_end(arg);
  282. if (micspk->opt & AMS_OPT_AS_ENGINE)
  283. LeaveCriticalSection(&micspk->engine_lock);
  284. return APR_SUCCESS;
  285. }
  286. void audiomicspk_disconnect_pipeline(audiomicspk_t *micspk, audiostream_t *stream)
  287. {
  288. audiostream_t *p;
  289. if (micspk->opt & AMS_OPT_AS_ENGINE)
  290. EnterCriticalSection(&micspk->engine_lock);
  291. micspk->engine_downstream = NULL;
  292. p = stream;
  293. while (p) {
  294. audiostream_t *next = p->downstream;
  295. p->direction = STREAM_DIR_NONE;
  296. p->upstream = NULL;
  297. p->downstream = NULL;
  298. p = next;
  299. }
  300. if (micspk->opt & AMS_OPT_AS_ENGINE)
  301. LeaveCriticalSection(&micspk->engine_lock);
  302. }
  303. void audiomicspk_lock(audiomicspk_t *micspk)
  304. {
  305. if (micspk->opt & AMS_OPT_AS_ENGINE)
  306. EnterCriticalSection(&micspk->engine_lock);
  307. }
  308. void audiomicspk_unlock(audiomicspk_t *micspk)
  309. {
  310. if (micspk->opt & AMS_OPT_AS_ENGINE)
  311. LeaveCriticalSection(&micspk->engine_lock);
  312. }