123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- #include "precompile.h"
- #include "audiomicspk.h"
- #include "audiocontext.h"
- #include "audiolog.h"
- #include "./other/delaybuf.h"
- #include <portaudio.h>
- #include <assert.h>
- #define MAX_DELAY 60
- static int get_device_index(int indev, const char *key)
- {
- int i;
- int n = Pa_GetDeviceCount();
- for (i = 0; i < n; ++i) {
- const PaDeviceInfo* pInfo = Pa_GetDeviceInfo(i);
- if (indev) {
- if (pInfo->maxInputChannels && strstr(pInfo->name, key))
- return i;
- } else {
- if (pInfo->maxOutputChannels && strstr(pInfo->name, key))
- return i;
- }
- }
- return -1;
- }
- static int StreamCallback(const void *input,
- void *output,
- unsigned long frameCount,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void *userData)
- {
- audiomicspk_t *micspk = userData;
- apr_status_t status;
- if (micspk->opt & AMS_OPT_AS_ENGINE) {
- audiostream_t *stream;
- EnterCriticalSection(&micspk->engine_lock);
- stream = micspk->engine_downstream;
- if (stream) {
- if (input && audiostream_get_direction(stream)&STREAM_DIR_WRITE) {
- audioframe_t frm = {(void*)input, frameCount<<1, 0};
- stream->vtbl->write_frame(stream, &frm);
- }
- if (output && audiostream_get_direction(stream)&STREAM_DIR_READ) {
- audioframe_t frm = {output, frameCount<<1, 0};
- status = stream->vtbl->read_frame(stream, &frm);
- if (status != APR_SUCCESS || frm.size != frameCount<<1) {
- memset(output, 0, frameCount<<1);
- }
- }
- }
- LeaveCriticalSection(&micspk->engine_lock);
- } else {
- if (input) {
- if (micspk->rec_buf_cnt == 0 && frameCount == micspk->frame_samples) {
- delay_buf_put(micspk->rec_dbuf, (short*)input);
- } else {
- unsigned long nsamples = frameCount + micspk->rec_buf_cnt;
- while (nsamples >= micspk->frame_samples) {
- unsigned chunk_count = micspk->frame_samples - micspk->rec_buf_cnt;
- memcpy(micspk->rec_buf+micspk->rec_buf_cnt, input, chunk_count<<1);
- input = (const short*)input + chunk_count;
- delay_buf_put(micspk->rec_dbuf, micspk->rec_buf);
- micspk->rec_buf_cnt = 0;
- nsamples -= micspk->frame_samples;
- }
- if (nsamples > 0) {
- memcpy(micspk->rec_buf+micspk->rec_buf_cnt, input, nsamples<<1);
- micspk->rec_buf_cnt += nsamples;
- }
- }
- }
- if (output) {
- unsigned nsamples_req = frameCount;
- if (micspk->ply_buf_cnt == 0 && nsamples_req == micspk->frame_samples) {
- delay_buf_get(micspk->ply_dbuf, (short*)output);
- } else {
- if (micspk->ply_buf_cnt > 0) {
- memcpy(output, micspk->ply_buf, micspk->ply_buf_cnt<<1);
- output = (short*)output + micspk->ply_buf_cnt;
- micspk->ply_buf_cnt = 0;
- nsamples_req -= micspk->ply_buf_cnt;
- }
- while (nsamples_req > 0) {
- if (nsamples_req >= micspk->frame_samples) {
- delay_buf_get(micspk->ply_dbuf, (short*)output);
- output = (short*)output + micspk->frame_samples;
- nsamples_req -= micspk->frame_samples;
- } else {
- delay_buf_get(micspk->ply_dbuf, micspk->ply_buf);
- micspk->ply_buf_cnt = micspk->frame_samples;
- memcpy(output, micspk->ply_buf, nsamples_req<<1);
- output = (short*)output + nsamples_req;
- memmove(micspk->ply_buf, micspk->ply_buf+nsamples_req, (micspk->frame_samples-nsamples_req)<<1);
- nsamples_req = 0;
- }
- }
- }
- }
- }
- return paContinue;
- }
- static apr_status_t read_frame(void *self, audioframe_t *frame)
- {
- audiomicspk_t *micspk = CONTAINING_RECORD(self, audiomicspk_t, base);
-
- frame->size = 2*micspk->frame_samples;
- frame->dtmf = 0;
- delay_buf_get(micspk->rec_dbuf, (short*)frame->buffer);
- return APR_SUCCESS;
- }
- static apr_status_t write_frame(void *self, const audioframe_t *frame)
- {
- audiomicspk_t *micspk = CONTAINING_RECORD(self, audiomicspk_t, base);
- assert(micspk->frame_samples*2 == frame->size);
- delay_buf_put(micspk->ply_dbuf, (short*)frame->buffer);
- return APR_SUCCESS;
- }
- static audiostream_vtbl_t g_stream_vtbl = {
- &read_frame,
- &write_frame,
- };
- apr_status_t audiomicspk_create(apr_pool_t *pool,
- audioengine_t *engine,
- int opt,
- int clock,
- const char *rec_dev_key,
- const char *ply_dev_key,
- audiomicspk_t **p_micspk)
- {
- int rec_dev_id = -1;
- int ply_dev_id = -1;
- audiomicspk_t *micspk;
- PaStreamParameters outParam;
- PaStreamParameters inParam;
- PaStream *pa_stream;
- unsigned long frame_samples;
- PaError paError;
- if (opt == 0) {
- AUDIO_LOG_ERROR("audiomicspk create error, opt cannot be zero");
- return APR_BADARG;
- }
- frame_samples = FRAME_TIME * clock / 1000;
- if (opt & AMS_OPT_PLAY) {
- if (ply_dev_key) {
- int id = get_device_index(0, ply_dev_key);
- if (id == -1) {
- AUDIO_LOG_ERROR("invalid play dev name!");
- return APR_BADARG;
- }
- ply_dev_id = id;
- }
- }
- if (opt & AMS_OPT_RECORD) {
- if (rec_dev_key) {
- int id = get_device_index(1, rec_dev_key);
- if (id == -1) {
- AUDIO_LOG_ERROR("invalid record dev name!");
- return APR_BADARG;
- }
- rec_dev_id = id;
- }
- }
- if (opt & AMS_OPT_PLAY) {
- const PaDeviceInfo *info;
- if (ply_dev_id == -1) {
- ply_dev_id = Pa_GetDefaultOutputDevice();
- if (ply_dev_id == paNoDevice) {
- AUDIO_LOG_ERROR("audiomicspk create error, cannot find output device");
- return -1;
- }
- }
- info = Pa_GetDeviceInfo(ply_dev_id);
- outParam.device = ply_dev_id;
- outParam.channelCount = 1;
- outParam.sampleFormat = paInt16;
- outParam.suggestedLatency = info->defaultLowOutputLatency;
- outParam.hostApiSpecificStreamInfo = NULL;
- if (Pa_IsFormatSupported(NULL, &outParam, clock) != paNoError) {
- AUDIO_LOG_ERROR("audiomicspk create error, cannot open audio output device");
- return -1;
- }
- AUDIO_LOG_ERROR("audio out suggestedLatency:%f, in:%f", info->defaultLowOutputLatency, info->defaultLowInputLatency);
- }
- if (opt & AMS_OPT_RECORD) {
- const PaDeviceInfo *info;
- if (rec_dev_id == -1) {
- rec_dev_id = Pa_GetDefaultInputDevice();
- if (rec_dev_id == paNoDevice) {
- AUDIO_LOG_ERROR("audiomicspk create error, cannot find input device");
- return -1;
- }
- }
- info = Pa_GetDeviceInfo(rec_dev_id);
- inParam.device = rec_dev_id;
- inParam.channelCount = 1;
- inParam.sampleFormat = paInt16;
- inParam.suggestedLatency = info->defaultLowInputLatency;
- inParam.hostApiSpecificStreamInfo = NULL;
- if (Pa_IsFormatSupported(&inParam, NULL, clock) != paNoError) {
- AUDIO_LOG_ERROR("audiomicspk create error, cannot open audio input device");
- return -1;
- }
- AUDIO_LOG_ERROR("audio in suggestedLatency:%f, out:%f", info->defaultLowInputLatency, info->defaultLowOutputLatency);;
- }
- micspk = apr_palloc(pool, sizeof(audiomicspk_t));
- memset(micspk, 0, sizeof(audiomicspk_t));
- paError = Pa_OpenStream(&pa_stream,
- (opt & AMS_OPT_RECORD) ? &inParam : NULL,
- (opt & AMS_OPT_PLAY) ? &outParam : NULL,
- clock, frame_samples,
- paClipOff,
- &StreamCallback,
- micspk);
- if (paError != 0) {
- AUDIO_LOG_ERROR("audiomicspk create error, Pa_OpenStream function failed in dir! ");
- return APR_EGENERAL;
- }
- audiostream_init(engine, &g_stream_vtbl, &micspk->base);
- micspk->base.direction = 0;
- if (opt & AMS_OPT_PLAY) {
- delay_buf_create(clock, frame_samples, 1, MAX_DELAY, 0, (delay_buf**)&micspk->ply_dbuf);
- micspk->base.direction |= STREAM_DIR_WRITE;
- micspk->ply_buf = (short*)apr_palloc(pool, frame_samples<<1);
- micspk->ply_buf_cnt = 0;
- }
- if (opt & AMS_OPT_RECORD) {
- micspk->base.direction |= STREAM_DIR_READ;
- delay_buf_create(clock, frame_samples, 1, MAX_DELAY, 0, (delay_buf**)&micspk->rec_dbuf);
- micspk->rec_buf = (short*)apr_palloc(pool, frame_samples<<1);
- micspk->rec_buf_cnt = 0;
- }
- if (opt & AMS_OPT_AS_ENGINE)
- InitializeCriticalSection(&micspk->engine_lock);
- micspk->clock = clock;
- micspk->opt = opt;
- micspk->frame_samples = frame_samples;
- micspk->rec_dev_id = rec_dev_id;
- micspk->ply_dev_id = ply_dev_id;
- micspk->stream = pa_stream;
- paError = Pa_StartStream(pa_stream);
- if (paError != 0) {
- AUDIO_LOG_ERROR("audiomicspk create error, Pa_StartStream function failed in dir! ");
- Pa_CloseStream(pa_stream);
- micspk->stream = NULL;
- audiomicspk_destroy(micspk);
- return APR_EGENERAL;
- }
- *p_micspk = micspk;
- return APR_SUCCESS;
- }
- void audiomicspk_destroy(audiomicspk_t *micspk)
- {
- if (micspk->stream) {
- Pa_AbortStream(micspk->stream);
- Pa_CloseStream(micspk->stream);
- }
- if (micspk->ply_dbuf)
- delay_buf_destroy(micspk->ply_dbuf);
- if (micspk->rec_dbuf)
- delay_buf_destroy(micspk->rec_dbuf);
- if (micspk->opt & AMS_OPT_AS_ENGINE)
- DeleteCriticalSection(&micspk->engine_lock);
- }
- apr_status_t audiomicspk_connect_pipeline(audiomicspk_t *micspk, int direction, ...)
- {
- va_list arg;
- audiostream_t *p, *q;
- if (micspk->opt & AMS_OPT_AS_ENGINE)
- EnterCriticalSection(&micspk->engine_lock);
- va_start(arg, direction);
- for (q = NULL, p = va_arg(arg, audiostream_t*); p; q = p, p = va_arg(arg, audiostream_t*)) {
- if (q == NULL) {
- micspk->engine_downstream = p;
- } else {
- q->downstream = p;
- }
- p->direction = direction;
- p->upstream = q;
- }
- if (q)
- q->downstream = NULL;
- va_end(arg);
- if (micspk->opt & AMS_OPT_AS_ENGINE)
- LeaveCriticalSection(&micspk->engine_lock);
- return APR_SUCCESS;
- }
- void audiomicspk_disconnect_pipeline(audiomicspk_t *micspk, audiostream_t *stream)
- {
- audiostream_t *p;
- if (micspk->opt & AMS_OPT_AS_ENGINE)
- EnterCriticalSection(&micspk->engine_lock);
- micspk->engine_downstream = NULL;
- p = stream;
- while (p) {
- audiostream_t *next = p->downstream;
- p->direction = STREAM_DIR_NONE;
- p->upstream = NULL;
- p->downstream = NULL;
- p = next;
- }
- if (micspk->opt & AMS_OPT_AS_ENGINE)
- LeaveCriticalSection(&micspk->engine_lock);
- }
- void audiomicspk_lock(audiomicspk_t *micspk)
- {
- if (micspk->opt & AMS_OPT_AS_ENGINE)
- EnterCriticalSection(&micspk->engine_lock);
- }
- void audiomicspk_unlock(audiomicspk_t *micspk)
- {
- if (micspk->opt & AMS_OPT_AS_ENGINE)
- LeaveCriticalSection(&micspk->engine_lock);
- }
|