| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557 |
- #include"libaudiomgr.h"
- #include "core_time.h"
- #include <stdlib.h>
- #include <string.h>
- #ifndef RVC_PA_ADJUST_LATENCY_PROTOCOL_VERSION
- #define RVC_PA_ADJUST_LATENCY_PROTOCOL_VERSION 13
- #endif
- static int sample_index = 0;
- // From pulsecore/macro.h
- #define pa_memzero(x,l) (memset((x), 0, (l)))
- #define pa_zero(x) (pa_memzero(&(x), sizeof(x)))
- static uint32_t latency_ms = 20; // requested initial latency in milisec: 0 use max
- static pa_usec_t latency = 0; //real latency in usec (for timestamping)
- static int sink_index = 0;
- static int source_index = 0;
- AudioMgrImpl::AudioMgrImpl(IAudioMgrCallback* pCallback)
- {
- m_audio_context = NULL;
- m_callback = pCallback;
- }
- AudioMgrImpl::~AudioMgrImpl()
- {
- if (NULL != m_audio_context){
- if (NULL != m_audio_context->list_input_devices) {
- free(m_audio_context->list_input_devices);
- m_audio_context->list_input_devices = NULL;
- }
- if (NULL != m_audio_context->list_output_devices) {
- free(m_audio_context->list_output_devices);
- m_audio_context->list_output_devices = NULL;
- }
- if (NULL != m_audio_context->capture_buff) {
- free(m_audio_context->capture_buff);
- m_audio_context->capture_buff = NULL;
- }
- free(m_audio_context);
- m_audio_context = NULL;
- }
- m_callback = NULL;
- }
- int AudioMgrImpl::audio_mgr_destroy()
- {
- delete this;
- return 0;
- }
- /*
- * init pulseaudio api
- * args:
- * audio_ctx - pointer to audio context data
- *
- * asserts:
- * audio_ctx is not null
- *
- * returns: error code (0 = E_OK)
- */
- int AudioMgrImpl::audio_init_pulseaudio()
- {
- /*assertions*/
- assert(NULL != m_audio_context);
- //if (false == m_initialized) {
- // // Initialize PulseAudio
- // if (InitPulseAudio() < 0) {
- // m_callback->debug("failed to initialize PulseAudio");
- // if (audio_mgr_terminate() < 0) {
- // m_callback->debug("failed to terminate PulseAudio");
- // }
- // return -1;
- // }
- // m_initialized = true;
- //}
- if (pa_get_devicelist() < 0)
- {
- m_callback->debug( "pulse audio failed to get audio device list from pulse server\n");
- return -1;
- }
- return 0;
- }
- //int32_t AudioMgrImpl::InitPulseAudio()
- //{
- //int retVal = 0;
- //// Create a mainloop API and connection to the default server
- //// the mainloop is the internal asynchronous API event loop
- //if (m_paMainloop) {
- // m_callback->debug("PA main loop has already existed");
- // return -1;
- //}
- //m_paMainloop = pa_mainloop_new();
- //if (!m_paMainloop) {
- // m_callback->debug("could not create main loop");;
- // return -1;
- //}
- //m_paMainloopApi = pa_mainloop_get_api(m_paMainloop);
- //if (!m_paMainloopApi) {
- // m_callback->debug("could not create main loop API");
- // return -1;
- //}
- //// Create a new PulseAudio context
- //if (m_paContext) {
- // m_callback->debug("PA context has already existed");
- // return -1;
- //}
- //m_paContext = pa_context_new(m_paMainloopApi, "RVC VoiceEngine");
- //if (!m_paContext) {
- // m_callback->debug("could not create context");
- // return -1;
- //}
- //if (pa_context_connect(m_paContext, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0)
- //{
- // m_callback->debug("AUDIO: PULSE - unable to connect to server: pa_context_connect failed");
- // return -1;
- //}
- //
- // return 0;
- //}
- /*
- * pa_mainloop will call this function when it's ready to tell us
- * about a source (input).
- * Since we're not threading when listing devices,
- * there's no need for mutexes on the devicelist structure
- * args:
- * c - pointer to pulse context
- * l - pointer to source info
- * eol - end of list
- * data - pointer to user data (audio context)
- *
- * asserts:
- * none
- *
- * returns: none
- */
- static void pa_sourcelist_cb(pa_context* c, const pa_source_info* l, int eol, void* data)
- {
- rvc_audio_context_t* audio_ctx = (rvc_audio_context_t*)data;
- int channels = 1;
- /*
- * If eol is set to a positive number,
- * you're at the end of the list
- */
- if (eol > 0)
- return;
- source_index++;
- if (l->sample_spec.channels < 1)
- channels = 1;
- else
- channels = l->sample_spec.channels;
- double my_latency = 0.0;
- int verbosity = 1;
- //if (verbosity > 0)
- //{
- //
- // printf("AUDIO: =======[ Input Device #%d ]=======\n", source_index);
- // printf(" Description: %s\n", l->description);
- // printf(" Name: %s\n", l->name);
- // printf(" Index: %d\n", l->index);
- // printf(" Channels: %d (default to: %d)\n", l->sample_spec.channels, channels);
- // printf(" SampleRate: %d\n", l->sample_spec.rate);
- // printf(" Latency: %llu (usec)\n", (long long unsigned) l->latency);
- // printf(" Configured Latency: %llu (usec)\n", (long long unsigned) l->configured_latency);
- // printf(" Card: %d\n", l->card);
- // printf(" monitor_of_sink_name: %s\n", l->monitor_of_sink_name);
- // printf(" driver: %s\n", l->driver);
- // if (l->active_port && l->active_port->name){
- // printf(" name: %s\n", l->active_port->name);
- // }
- // if (l->active_port && l->active_port->description){
- // printf(" description name: %s\n", l->active_port->description);
- // }
- // printf(" Volume channels: %d\n", l->volume.channels);
- // for(int i = 0; i < l->volume.channels; i++) {
- // printf(" Volume value: %d\n", l->volume.values[i]);
- // }
- // printf("\n");
- //}
- if (my_latency <= 0.0)
- my_latency = (double)latency_ms / 1000;
- if (l->monitor_of_sink == PA_INVALID_INDEX)
- {
- audio_ctx->num_input_dev++;
- /*add device to list*/
- audio_ctx->list_input_devices = (rvc_audio_device_t*)realloc(audio_ctx->list_input_devices, audio_ctx->num_input_dev * sizeof(rvc_audio_device_t));
- if (audio_ctx->list_input_devices == NULL)
- {
- //printf("AUDIO: FATAL memory allocation failure (pa_sourcelist_cb): %s\n", strerror(errno));
- exit(-1);
- }
- /*fill device data*/
- audio_ctx->list_input_devices[audio_ctx->num_input_dev - 1].id = l->index; /*saves dev id*/
- strncpy(audio_ctx->list_input_devices[audio_ctx->num_input_dev - 1].name, l->name, MAX_PATH_EX-1);
- strncpy(audio_ctx->list_input_devices[audio_ctx->num_input_dev - 1].description, l->description, MAX_PATH-1);
- audio_ctx->list_input_devices[audio_ctx->num_input_dev - 1].channels = channels;
- audio_ctx->list_input_devices[audio_ctx->num_input_dev - 1].samprate = l->sample_spec.rate;
- audio_ctx->list_input_devices[audio_ctx->num_input_dev - 1].low_latency = my_latency; /*in seconds*/
- audio_ctx->list_input_devices[audio_ctx->num_input_dev - 1].high_latency = my_latency; /*in seconds*/
- }
- }
- void PaSetVolumeCallback(pa_context* c,
- int success,
- void* /*pThis*/) {
- if (!success) {
- //printf("failed to set volume\n");
- }
- else {
- //printf("success to set volume\n");
- }
- }
- static void pa_setsourcevolume_cb(pa_context* c, const pa_source_info* l, int eol, void* data)
- {
- rvc_volume_set_t* audio_volume = (rvc_volume_set_t*)data;
- /*
- * If eol is set to a positive number,
- * you're at the end of the list
- */
- if (eol > 0)
- return;
- if (l->monitor_of_sink == PA_INVALID_INDEX)
- {
- if (strstr(l->description, audio_volume->strdevicename)) {
- pa_cvolume cvolumes;
- // Set the same volume for all channels
- pa_cvolume_set(&cvolumes, l->channel_map.channels, audio_volume->ivolume);
- pa_operation* paOperation = NULL;
- if (!(paOperation = pa_context_set_source_volume_by_index(c, l->index, &cvolumes, PaSetVolumeCallback, NULL))) {
- audio_volume->volume_flag = 1;
- }
-
- pa_operation_unref(paOperation);
- }
- }
- }
- static void pa_setsinkvolume_cb(pa_context* c, const pa_sink_info* l, int eol, void* data)
- {
- rvc_volume_set_t* audio_volume = (rvc_volume_set_t*)data;
- /*
- * If eol is set to a positive number,
- * you're at the end of the list
- */
- if (eol > 0)
- return;
- if (strstr(l->description, audio_volume->strdevicename)) {
- pa_cvolume cvolumes;
- // Set the same volume for all channels
- pa_cvolume_set(&cvolumes, l->channel_map.channels, audio_volume->ivolume);
- pa_operation* paOperation = NULL;
- if (!(paOperation = pa_context_set_sink_volume_by_index(c, l->index, &cvolumes, PaSetVolumeCallback, NULL))) {
- audio_volume->volume_flag = 1;
- }
- pa_operation_unref(paOperation);
- }
- }
- static void pa_sourcevolume_cb(pa_context* c, const pa_source_info* l, int eol, void* data)
- {
- rvc_audio_volume_t* audio_volume = (rvc_audio_volume_t*)data;
- /*
- * If eol is set to a positive number,
- * you're at the end of the list
- */
- if (eol > 0)
- return;
- //{
- // printf("AUDIO: =======[ Input Device #%d ]=======\n", source_index);
- // printf(" Description: %s\n", l->description);
- // printf(" Name: %s\n", l->name);
- // printf(" Index: %d\n", l->index);
- // printf(" SampleRate: %d\n", l->sample_spec.rate);
- // printf(" Latency: %llu (usec)\n", (long long unsigned) l->latency);
- // printf(" Configured Latency: %llu (usec)\n", (long long unsigned) l->configured_latency);
- // printf(" Card: %d\n", l->card);
- // printf(" monitor_of_sink_name: %s\n", l->monitor_of_sink_name);
- // printf(" driver: %s\n", l->driver);
- // if (l->active_port && l->active_port->name) {
- // printf(" name: %s\n", l->active_port->name);
- // }
- // if (l->active_port && l->active_port->description) {
- // printf(" description name: %s\n", l->active_port->description);
- // }
- // printf(" Volume channels: %d\n", l->volume.channels);
- // for (int i = 0; i < l->volume.channels; i++) {
- // printf(" Volume value: %d\n", l->volume.values[i]);
- // }
- // printf("\n");
- //}
- if (l->monitor_of_sink == PA_INVALID_INDEX)
- {
- if (strstr(l->description, audio_volume->strdevicename)){
- audio_volume->cvolumes = l->volume;
- audio_volume->volume_flag = 1;
- }
- }
- }
- static void pa_sinkvolume_cb(pa_context* c, const pa_sink_info* l, int eol, void* userdata)
- {
- rvc_audio_volume_t* audio_volume = (rvc_audio_volume_t*)userdata;
- /*
- * If eol is set to a positive number,
- * you're at the end of the list
- */
- if (eol > 0)
- return;
- //{
- // printf("AUDIO: =======[ Output Device #%d ]=======\n", sink_index);
- // printf(" Description: %s\n", l->description);
- // printf(" Name: %s\n", l->name);
- // printf(" Index: %d\n", l->index);
- // printf(" Channels: %d\n", l->channel_map.channels);
- // printf(" SampleRate: %d\n", l->sample_spec.rate);
- // printf(" Latency: %llu (usec)\n", (long long unsigned) l->latency);
- // printf(" Configured Latency: %llu (usec)\n", (long long unsigned) l->configured_latency);
- // printf(" Card: %d\n", l->card);
- // printf(" monitor_of_sink_name: %s\n", l->monitor_source_name);
- // printf(" driver: %s\n", l->driver);
- // printf(" n_ports: %d\n", l->n_ports);
- // printf(" name: %s\n", l->active_port->name);
- // printf(" description name: %s\n", l->active_port->description);
- // printf(" Volume channels: %d\n", l->volume.channels);
- // for (int i = 0; i < l->volume.channels; i++) {
- // printf(" Volume value: %d\n", l->volume.values[i]);
- // }
- // printf("\n");
- //}
- if (strstr(l->description, audio_volume->strdevicename)) {
- audio_volume->cvolumes = l->volume;
- audio_volume->volume_flag = 1;
- }
- //{
- // pa_cvolume cvolumes;
- // // Set the same volume for all channels
- // int ivolume = 65536;
- // pa_cvolume_set(&cvolumes, l->channel_map.channels, ivolume);
- // printf("%s:%d. audio_dev->id = %d, audio_dev->channels = %d, ivolume = %d.\n", __FUNCTION__, __LINE__, l->index, l->channel_map.channels, ivolume);
- // for (int i = 0; i < cvolumes.channels; i++) {
- // printf("%s:%d. cvolumes.values[%d] = %d.\n", __FUNCTION__, __LINE__, i, cvolumes.values[i]);
- // }
- // pa_operation* paOperation = NULL;
- // if (!(paOperation = pa_context_set_sink_volume_by_name(c, l->name, &cvolumes, PaSetVolumeCallback, NULL))) {
- // printf("pa_context_set_sink_volume_by_index() failed\n");
- // return;
- // }
- // pa_operation_unref(paOperation);
- //}
- }
- /*
- * pa_mainloop will call this function when it's ready to tell us
- * about a source (input).
- * This callback is pretty much identical to the previous
- * but it will only print the output devices
- * args:
- * c - pointer to pulse context
- * l - pointer to sink info
- * eol - end of list
- * data - pointer to user data (audio context)
- *
- * asserts:
- * none
- *
- * returns: none
- */
- static void pa_sinklist_cb(pa_context* c, const pa_sink_info* l, int eol, void* userdata)
- {
- rvc_audio_context_t* audio_ctx = (rvc_audio_context_t*)userdata;
- /*
- * If eol is set to a positive number,
- * you're at the end of the list
- */
- if (eol > 0)
- return;
- sink_index++;
- double my_latency = 0.0;
- int verbosity = 1;
- //if (verbosity > 0)
- //{
- // printf("AUDIO: =======[ Output Device #%d ]=======\n", sink_index);
- // printf(" Description: %s\n", l->description);
- // printf(" Name: %s\n", l->name);
- // printf(" Index: %d\n", l->index);
- // printf(" Channels: %d\n", l->channel_map.channels);
- // printf(" SampleRate: %d\n", l->sample_spec.rate);
- // printf(" Latency: %llu (usec)\n", (long long unsigned) l->latency);
- // printf(" Configured Latency: %llu (usec)\n", (long long unsigned) l->configured_latency);
- // printf(" Card: %d\n", l->card);
- // printf(" monitor_of_sink_name: %s\n", l->monitor_source_name);
- // printf(" driver: %s\n", l->driver);
- // printf(" n_ports: %d\n", l->n_ports);
- // printf(" name: %s\n", l->active_port->name);
- // printf(" description name: %s\n", l->active_port->description);
- // printf(" Volume channels: %d\n", l->volume.channels);
- // for (int i = 0; i < l->volume.channels; i++) {
- // printf(" Volume value: %d\n", l->volume.values[i]);
- // }
- // printf("\n");
- //}
- if (my_latency <= 0.0)
- my_latency = (double)latency_ms / 1000;
- audio_ctx->num_output_dev++;
- /*add device to list*/
- audio_ctx->list_output_devices = (rvc_audio_device_t*)realloc(audio_ctx->list_output_devices, audio_ctx->num_output_dev * sizeof(rvc_audio_device_t));
- if (audio_ctx->list_output_devices == NULL)
- {
- printf("AUDIO: FATAL memory allocation failure (pa_sinklist_cb): %s\n", strerror(errno));
- exit(-1);
- }
- /*fill device data*/
- audio_ctx->list_output_devices[audio_ctx->num_output_dev - 1].id = l->index; /*saves dev id*/
- strncpy(audio_ctx->list_output_devices[audio_ctx->num_output_dev - 1].name, l->name, MAX_PATH_EX-1);
- strncpy(audio_ctx->list_output_devices[audio_ctx->num_output_dev - 1].description, l->description, MAX_PATH-1);
- audio_ctx->list_output_devices[audio_ctx->num_output_dev - 1].channels = l->channel_map.channels;
- audio_ctx->list_output_devices[audio_ctx->num_output_dev - 1].samprate = l->sample_spec.rate;
- audio_ctx->list_output_devices[audio_ctx->num_output_dev - 1].low_latency = my_latency; /*in seconds*/
- audio_ctx->list_output_devices[audio_ctx->num_output_dev - 1].high_latency = my_latency; /*in seconds*/
- }
- /*
- * This callback gets called when our context changes state.
- * We really only care about when it's ready or if it has failed
- * args:
- * c -pointer to pulse context
- * data - pointer to user data
- *
- * asserts:
- * none
- *
- * retuns: none
- */
- static void pa_state_cb(pa_context* c, void* data)
- {
- pa_context_state_t state;
- int* pa_ready = (int*)data;
- state = pa_context_get_state(c);
- switch (state)
- {
- // These are just here for reference
- case PA_CONTEXT_UNCONNECTED:
- //printf("unconnected\n");
- break;
- case PA_CONTEXT_CONNECTING:
- case PA_CONTEXT_AUTHORIZING:
- case PA_CONTEXT_SETTING_NAME:
- default:
- //printf("no state\n");
- break;
- case PA_CONTEXT_FAILED:
- case PA_CONTEXT_TERMINATED:
- *pa_ready = 2;
- //printf("failed\n");
- break;
- case PA_CONTEXT_READY:
- *pa_ready = 1;
- //printf("ready\n");
- break;
- }
- }
- /*
- * clean up and disconnect
- * args:
- * pa_ctx - pointer to pulse context
- * pa_ml - pointer to pulse mainloop
- *
- * asserts:
- * none
- *
- * returns:
- * none
- */
- static void finish(pa_context* pa_ctx, pa_mainloop* pa_ml)
- {
- /* clean up and disconnect */
- pa_context_disconnect(pa_ctx);
- pa_context_unref(pa_ctx);
- pa_mainloop_free(pa_ml);
- }
- /*
- * iterate the main loop until all devices are listed
- * args:
- * audio_ctx - pointer to audio context
- *
- * asserts:
- * audio_ctx is not null
- *
- * returns: error code
- */
- int AudioMgrImpl::pa_get_devicelist()
- {
- /*assertions*/
- assert(m_audio_context != NULL);
- /* Define our pulse audio loop and connection variables */
- pa_mainloop* pa_ml;
- pa_mainloop_api* pa_mlapi;
- pa_operation* pa_op = NULL;
- pa_context* pa_ctx;
- /* We'll need these state variables to keep track of our requests */
- int state = 0;
- int pa_ready = 0;
- /* Create a mainloop API and connection to the default server */
- pa_ml = pa_mainloop_new();
- pa_mlapi = pa_mainloop_get_api(pa_ml);
- pa_ctx = pa_context_new(pa_mlapi, "getDevices");
- /* This function connects to the pulse server */
- if (pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0)
- {
- if(m_callback)
- m_callback->debug("AUDIO: PULSE - unable to connect to server: pa_context_connect failed");
- finish(pa_ctx, pa_ml);
- return -1;
- }
- /*
- * This function defines a callback so the server will tell us
- * it's state.
- * Our callback will wait for the state to be ready.
- * The callback will modify the variable to 1 so we know when we
- * have a connection and it's ready.
- * If there's an error, the callback will set pa_ready to 2
- */
- pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);
- /*
- * Now we'll enter into an infinite loop until we get the data
- * we receive or if there's an error
- */
- for (;;)
- {
- /*
- * We can't do anything until PA is ready,
- * so just iterate the mainloop and continue
- */
- if (pa_ready == 0)
- {
- pa_mainloop_iterate(pa_ml, 1, NULL);
- continue;
- }
- ///* We couldn't get a connection to the server, so exit out */
- if (pa_ready == 2)
- {
- finish(pa_ctx, pa_ml);
- return -1;
- }
- /*
- * At this point, we're connected to the server and ready
- * to make requests
- */
- switch (state)
- {
- /* State 0: we haven't done anything yet */
- case 0:
- /*
- * This sends an operation to the server.
- * pa_sinklist_cb is our callback function and a pointer
- * o our devicelist will be passed to the callback
- * (audio_ctx) The operation ID is stored in the
- * pa_op variable
- */
- pa_op = pa_context_get_sink_info_list(
- pa_ctx,
- pa_sinklist_cb,
- (void*)m_audio_context);
- /* Update state for next iteration through the loop */
- state++;
- break;
- case 1:
- /*
- * Now we wait for our operation to complete.
- * When it's complete our pa_output_devicelist is
- * filled out, and we move along to the next state
- */
- if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE)
- {
- pa_operation_unref(pa_op);
- /*
- * Now we perform another operation to get the
- * source(input device) list just like before.
- * This time we pass a pointer to our input structure
- */
- pa_op = pa_context_get_source_info_list(
- pa_ctx,
- pa_sourcelist_cb,
- (void*)m_audio_context);
- /* Update the state so we know what to do next */
- state++;
- }
- break;
- case 2:
- if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE)
- {
- /*
- * Now we're done,
- * clean up and disconnect and return
- */
- pa_operation_unref(pa_op);
- finish(pa_ctx, pa_ml);
- return 0;
- }
- break;
- default:
- /* We should never see this state */
- if(m_callback)
- m_callback->debug("AUDIO: Pulse audio in state %d", state);
- return -1;
- }
- /*
- * Iterate the main loop and go again. The second argument is whether
- * or not the iteration should block until something is ready to be
- * done. Set it to zero for non-blocking.
- */
- pa_mainloop_iterate(pa_ml, 1, NULL);
- }
- finish(pa_ctx, pa_ml);
- return 0;
- }
- /*
- * get the number of available audio devices
- *
- * args:
- * binput - is input device
- * asserts:
- * audio_ctx is not null
- *
- * returns: number of listed audio devices
- */
- int AudioMgrImpl::audio_get_device_count(bool binput)
- {
- /*assertions*/
- assert(m_audio_context != NULL);
- if (binput){
- return m_audio_context->num_input_dev;
- }
- else {
- return m_audio_context->num_output_dev;
- }
-
- }
- /*
- * get the audio device referenced by index
- * args:
- * index - index of audio device
- *
- * asserts:
- * audio_ctx is not null
- *
- * returns: audio device referenced by index
- */
- rvc_audio_device_t* AudioMgrImpl::audio_get_input_device(int index)
- {
- /*assertions*/
- assert(m_audio_context != NULL);
- if (index >= m_audio_context->num_input_dev){
- //printf("AUDIO: (audio_get_input_device) bad index %i using %i\n",index, m_audio_context->num_input_dev - 1);
- index = m_audio_context->num_input_dev - 1;
- }
- if (index < 0){
- //printf("AUDIO: (audio_get_input_device) bad index %i using 0\n", index);
- index = 0;
- }
- return &m_audio_context->list_input_devices[index];
- }
- /*
- * get the output audio device referenced by index
- * args:
- * index - index of output audio device
- *
- * asserts:
- * audio_ctx is not null
- *
- * returns: output audio device referenced by index
- */
- rvc_audio_device_t* AudioMgrImpl::audio_get_output_device( int index)
- {
- /*assertions*/
- assert(m_audio_context != NULL);
- if (index >= m_audio_context->num_output_dev)
- {
- //printf("AUDIO: (audio_get_output_device) bad index %i using %i\n",index, m_audio_context->num_output_dev - 1);
- index = m_audio_context->num_output_dev - 1;
- }
- if (index < 0)
- {
- //printf("AUDIO: (audio_get_output_device) bad index %i using 0\n", index);
- index = 0;
- }
- return &m_audio_context->list_output_devices[index];
- }
- int AudioMgrImpl::audio_get_device_name(char* pstrbuf, size_t ulen, bool binput, int index)
- {
- int iret = -1;
- //模拟立体声
- const char stranalogstereo[] = { 0x20,0xe6,0xa8,0xa1,0xe6,0x8b,0x9f,0xe7,0xab,0x8b,0xe4,0xbd,0x93,0xe5,0xa3,0xb0,0 };
- //数字立体声
- const char strdigitalstereo[] = { 0x20,0xe6,0x95,0xb0,0xe5,0xad,0x97,0xe7,0xab,0x8b,0xe4,0xbd,0x93,0xe5,0xa3,0xb0,0 };
- //立体声
- const char strstereo[] = { 0x20,0xe7,0xab,0x8b,0xe4,0xbd,0x93,0xe5,0xa3,0xb0,0 };
- //多声道
- const char strmultistereo[] = { 0x20,0xe5,0xa4,0x9a,0xe5,0xa3,0xb0,0xe9,0x81,0x93,0 };
- rvc_audio_device_t* audio_device = NULL;
- if (binput){
- audio_device = audio_get_input_device(index);
- }
- else{
- audio_device = audio_get_output_device(index);
- }
-
- size_t unamelen = strlen(audio_device->description);
- if (ulen > unamelen){
- memcpy(pstrbuf, audio_device->description, ulen);
- char* pindex = NULL;
- if ((pindex = strstr(pstrbuf, stranalogstereo))||(pindex = strstr(pstrbuf, strdigitalstereo))){
- *pindex = 0;
- }
- if ((pindex = strstr(pstrbuf, strstereo)) || (pindex = strstr(pstrbuf, strmultistereo))) {
- *pindex = 0;
- }
- iret = 0;
- }
- return iret;
- }
- int AudioMgrImpl::audio_get_device_id(const char* pstrname, bool binput)
- {
- int iret = -1;
- if (NULL == pstrname){
- return iret;
- }
- int icount = audio_get_device_count(binput);
- if (icount > 0){
- for (int index = 0; index < icount; index++){
- rvc_audio_device_t* audio_device = NULL;
- if (binput) {
- audio_device = audio_get_input_device(index);
- }
- else {
- audio_device = audio_get_output_device(index);
- }
- if (NULL != audio_device){
- if (strstr(audio_device->description, pstrname)){
- iret = index;
- break;
- }
- }
- }
- }
- return iret;
- }
- int AudioMgrImpl::audio_get_device_volume(int* ivolume, const char* pstrname, bool binput)
- {
- int iret = -1;
- pa_mainloop* pa_ml;
- pa_mainloop_api* pa_mlapi;
- pa_operation* pa_op = NULL;
- pa_context* pa_ctx;
- /* We'll need these state variables to keep track of our requests */
- int state = 0;
- int pa_ready = 0;
- rvc_audio_volume_t rvc_volume = { 0 };
- strcpy(rvc_volume.strdevicename, pstrname);
- /* Create a mainloop API and connection to the default server */
- pa_ml = pa_mainloop_new();
- pa_mlapi = pa_mainloop_get_api(pa_ml);
- pa_ctx = pa_context_new(pa_mlapi, "get audio volume");
- /* This function connects to the pulse server */
- if (pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0)
- {
- if(m_callback)
- m_callback->debug("AUDIO: PULSE - unable to connect to server: pa_context_connect failed");
- finish(pa_ctx, pa_ml);
- return -1;
- }
- /*
- * This function defines a callback so the server will tell us
- * it's state.
- * Our callback will wait for the state to be ready.
- * The callback will modify the variable to 1 so we know when we
- * have a connection and it's ready.
- * If there's an error, the callback will set pa_ready to 2
- */
- pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);
- /*
- * Now we'll enter into an infinite loop until we get the data
- * we receive or if there's an error
- */
- for (;;)
- {
- /*
- * We can't do anything until PA is ready,
- * so just iterate the mainloop and continue
- */
- if (pa_ready == 0)
- {
- pa_mainloop_iterate(pa_ml, 1, NULL);
- continue;
- }
- ///* We couldn't get a connection to the server, so exit out */
- if (pa_ready == 2)
- {
- finish(pa_ctx, pa_ml);
- return -1;
- }
- /*
- * At this point, we're connected to the server and ready
- * to make requests
- */
- if (0 == state){
- if (binput) {
- pa_op = pa_context_get_source_info_list(
- pa_ctx,
- pa_sourcevolume_cb,
- (void*)& rvc_volume);
- }
- else
- {
- pa_op = pa_context_get_sink_info_list(
- pa_ctx,
- pa_sinkvolume_cb,
- (void*)& rvc_volume);
- }
- state++;
- }
- if (rvc_volume.volume_flag){
- *ivolume = rvc_volume.cvolumes.values[0];
- pa_operation_unref(pa_op);
- break;
- }
- if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE)
- {
- /*
- * Now we're done,
- * clean up and disconnect and return
- */
- pa_operation_unref(pa_op);
- finish(pa_ctx, pa_ml);
- return 0;
- }
- /*
- * Iterate the main loop and go again. The second argument is whether
- * or not the iteration should block until something is ready to be
- * done. Set it to zero for non-blocking.
- */
- pa_mainloop_iterate(pa_ml, 1, NULL);
- }
- finish(pa_ctx, pa_ml);
- return iret;
- }
- int AudioMgrImpl::audio_set_device_volume(int ivolume, const char* pstrname, bool binput)
- {
- int iret = -1;
- pa_mainloop* pa_ml;
- pa_mainloop_api* pa_mlapi;
- pa_operation* pa_op = NULL;
- pa_context* pa_ctx;
- /* We'll need these state variables to keep track of our requests */
- int state = 0;
- int pa_ready = 0;
- rvc_volume_set_t rvc_volume = { 0 };
- strcpy(rvc_volume.strdevicename, pstrname);
- rvc_volume.ivolume = ivolume;
- /* Create a mainloop API and connection to the default server */
- pa_ml = pa_mainloop_new();
- pa_mlapi = pa_mainloop_get_api(pa_ml);
- pa_ctx = pa_context_new(pa_mlapi, "set audio volume");
- /* This function connects to the pulse server */
- if (pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0)
- {
- if (m_callback)
- m_callback->debug("AUDIO: PULSE - unable to connect to server: pa_context_connect failed");
- finish(pa_ctx, pa_ml);
- return -1;
- }
- /*
- * This function defines a callback so the server will tell us
- * it's state.
- * Our callback will wait for the state to be ready.
- * The callback will modify the variable to 1 so we know when we
- * have a connection and it's ready.
- * If there's an error, the callback will set pa_ready to 2
- */
- pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);
- /*
- * Now we'll enter into an infinite loop until we get the data
- * we receive or if there's an error
- */
- for (;;)
- {
- /*
- * We can't do anything until PA is ready,
- * so just iterate the mainloop and continue
- */
- if (pa_ready == 0)
- {
- pa_mainloop_iterate(pa_ml, 1, NULL);
- continue;
- }
- ///* We couldn't get a connection to the server, so exit out */
- if (pa_ready == 2)
- {
- finish(pa_ctx, pa_ml);
- return -1;
- }
- /*
- * At this point, we're connected to the server and ready
- * to make requests
- */
- if (0 == state) {
- if (binput) {
- pa_op = pa_context_get_source_info_list(
- pa_ctx,
- pa_setsourcevolume_cb,
- (void*)&rvc_volume);
- }
- else
- {
- pa_op = pa_context_get_sink_info_list(
- pa_ctx,
- pa_setsinkvolume_cb,
- (void*)&rvc_volume);
- }
- state++;
- }
- if (rvc_volume.volume_flag) {
- pa_operation_unref(pa_op);
- break;
- }
- if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE)
- {
- /*
- * Now we're done,
- * clean up and disconnect and return
- */
- pa_operation_unref(pa_op);
- finish(pa_ctx, pa_ml);
- return 0;
- }
- /*
- * Iterate the main loop and go again. The second argument is whether
- * or not the iteration should block until something is ready to be
- * done. Set it to zero for non-blocking.
- */
- pa_mainloop_iterate(pa_ml, 1, NULL);
- }
- finish(pa_ctx, pa_ml);
- return iret;
- }
- int AudioMgrImpl::audio_mgr_initialize()
- {
- int iret = -1;
- m_audio_context = (rvc_audio_context_t*)calloc(1, sizeof(rvc_audio_context_t));
- if (NULL == m_audio_context){
- if (m_callback)
- m_callback->debug("%s:%d couldn't allocate audio context.", __FUNCTION__, __LINE__);
- return iret;
- }
- iret = audio_init_pulseaudio();
- /*force a valid number of channels*/
- if (m_audio_context->channels > 2) {
- m_audio_context->channels = 2;
- }
-
- return iret;
- }
- /*
- * close and clean audio context for pulse audio api
- *
- * asserts:
- * none
- *
- * returns: none
- */
- int AudioMgrImpl::audio_close_pulseaudio()
- {
- int iret = -1;
- if (m_audio_context == NULL){
- return iret;
- }
- if (m_audio_context->stream_flag == AUDIO_STRM_ON) {
- stop_audio_capture();
- }
-
- if (NULL != m_audio_context->list_input_devices) {
- free(m_audio_context->list_input_devices);
- m_audio_context->list_input_devices = NULL;
- }
- if (NULL != m_audio_context->list_output_devices){
- free(m_audio_context->list_output_devices);
- m_audio_context->list_output_devices = NULL;
- }
- if (NULL != m_audio_context->capture_buff) {
- free(m_audio_context->capture_buff);
- m_audio_context->capture_buff = NULL;
- }
-
- free(m_audio_context);
- m_audio_context = NULL;
- iret = 0;
- return iret;
- }
- /*
- * stop and join the main loop iteration thread
- *
- * asserts:
- * audio_ctx is not null
- *
- * returns: error code
- */
- int AudioMgrImpl::stop_audio_capture()
- {
- /*assertions*/
- assert(m_audio_context != NULL);
- m_audio_context->stream_flag = AUDIO_STRM_OFF;
- if (0 == __THREAD_JOIN(m_readthread)){
- if (m_callback)
- m_callback->debug("read thread join success!");
- }
- else{
- if (m_callback)
- m_callback->debug("read thread join failed!");
- }
- return 0;
- }
- int AudioMgrImpl::audio_mgr_terminate()
- {
- int iret = -1;
- /*assertions*/
- assert(m_audio_context != NULL);
- /* thread must be joined before destroying the mutex
- * so no need to unlock before destroying it
- */
- iret = audio_close_pulseaudio();
- //if (!m_paMainloop) {
- // return 0;
- //}
- //// Disconnect the context
- //if (m_paContext) {
- // (pa_context_disconnect)(m_paContext);
- //}
- //// Unreference the context
- //if (m_paContext) {
- // (pa_context_unref)(m_paContext);
- //}
- //m_paContext = NULL;
- //
- //pa_mainloop_free(m_paMainloop);
- //m_paMainloop = NULL;
- return iret;
- }
- /*
- * update pulse audio latency
- * args:
- * s - pointer to pa_stream
- *
- * asserts:
- * none
- *
- * returns:none
- */
- static void get_latency(pa_stream* s)
- {
- pa_usec_t l;
- int negative;
- pa_stream_get_timing_info(s);
- if (pa_stream_get_latency(s, &l, &negative) != 0)
- {
- fprintf(stderr, "AUDIO: Pulseaudio pa_stream_get_latency() failed\n");
- return;
- }
- //latency = l * (negative?-1:1);
- latency = l; /*can only be negative in monitoring streams*/
- }
- /*
- * audio record callback
- * args:
- * s - pointer to pa_stream
- * length - buffer length
- * data - pointer to user data
- *
- * asserts:
- * none
- *
- * returns: none
- */
- static void stream_request_cb(pa_stream* s, size_t length, void* data)
- {
- rvc_audio_context_t* audio_ctx = (rvc_audio_context_t*)data;
- if (audio_ctx->channels == 0){
- return;
- }
- if (audio_ctx->samprate == 0){
- return;
- }
- uint64_t frame_length = NSEC_PER_SEC / audio_ctx->samprate; /*in nanosec*/
- int64_t ts = 0;
- int64_t buff_ts = 0;
- uint32_t i = 0;
- while (pa_stream_readable_size(s) > 0)
- {
- const void* inputBuffer;
- size_t length;
- /*read from stream*/
- if (pa_stream_peek(s, &inputBuffer, &length) < 0){
- return;
- }
- else {
- //printf("%s:%d pa_stream_peek audio length is %d.\n", __FUNCTION__, __LINE__, length);
- }
- if (length == 0)
- {
- return; /*buffer is empty*/
- }
- get_latency(s);
- ts = ns_time_monotonic() - (latency * 1000);
- if (audio_ctx->last_ts <= 0)
- audio_ctx->last_ts = ts;
- uint32_t numSamples = (uint32_t)length / sizeof(sample_t);
- audio_ctx->audio_param.on_audio_callback(inputBuffer, length, audio_ctx->audio_param.user_data);
- pa_stream_drop(s); /*clean the samples*/
- }
- }
- /*
- * Iterate the main loop while recording is on.
- * This function runs under it's own thread called by audio_pulse_start
- * args:
- * data - pointer to user data (audio context)
- *
- * asserts:
- * data is not null
- *
- * returns: pointer to error code
- */
- void* pulse_read_audio(void* data)
- {
- AudioMgrImpl* audio_mgr = (AudioMgrImpl*)data;
- assert(audio_mgr != NULL);
- IAudioMgrCallback* callback = audio_mgr->audio_get_callback();
- assert(callback != NULL);
- rvc_audio_context_t* audio_ctx = audio_mgr->audio_get_context();
- /*assertions*/
- assert(audio_ctx != NULL);
-
- pa_mainloop* pa_ml;
- pa_mainloop_api* pa_mlapi;
- pa_buffer_attr bufattr;
- pa_stream* recordstream = NULL; // pulse audio stream
- pa_context* pa_ctx; //pulse context
- pa_sample_spec ss;
- pa_stream_flags_t flags = PA_STREAM_NOFLAGS;
- int32_t pastream_flag = (int32_t)PA_STREAM_NOFLAGS;
- int r;
- int pa_ready = 0;
- /* Create a mainloop API and connection to the default server */
- pa_ml = pa_mainloop_new();
- pa_mlapi = pa_mainloop_get_api(pa_ml);
- pa_ctx = pa_context_new(pa_mlapi, "rvc pulse API");
- if (pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0)
- {
- callback->debug("AUDIO: PULSE - unable to connect to server: pa_context_connect failed.");
- finish(pa_ctx, pa_ml);
- return ((void*)-1);
- }
- /*
- * This function defines a callback so the server will tell us it's state.
- * Our callback will wait for the state to be ready. The callback will
- * modify the variable to 1 so we know when we have a connection and it's
- * ready.
- * If there's an error, the callback will set pa_ready to 2
- */
- pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);
- /*
- * This function defines a time event callback (called every TIME_EVENT_USEC)
- */
- //pa_context_rttime_new(pa_ctx, pa_rtclock_now() + TIME_EVENT_USEC, time_event_callback, NULL);
- /*
- * We can't do anything until PA is ready, so just iterate the mainloop
- * and continue
- */
- while (pa_ready == 0){
- pa_mainloop_iterate(pa_ml, 1, NULL);
- }
- if (pa_ready == 2){
- finish(pa_ctx, pa_ml);
- return ((void*)-1);
- }
- /* set the sample spec (frame rate, channels and format) */
- ss.rate = audio_ctx->samprate;
- ss.channels = audio_ctx->channels;
- ss.format = audio_ctx->eformat/*PA_SAMPLE_FLOAT32LE*/; /*for PCM -> PA_SAMPLE_S16LE*/
- recordstream = pa_stream_new(pa_ctx, "Record", &ss, NULL);
- if (!recordstream)
- callback->debug("AUDIO: (pulse audio) pa_stream_new failed (chan:%d rate:%d)",
- ss.channels, ss.rate);
- /* define the callbacks */
- pa_stream_set_read_callback(recordstream, stream_request_cb, (void*)audio_ctx);
- // Set properties of the record buffer
- pa_zero(bufattr);
- /* optimal value for all is (uint32_t)-1 ~= 2 sec */
- bufattr.maxlength = (uint32_t)-1;
- bufattr.prebuf = (uint32_t)-1;
- bufattr.minreq = (uint32_t)-1;
- if (audio_ctx->latency > 0){
- bufattr.fragsize = bufattr.tlength = pa_usec_to_bytes((audio_ctx->latency * 1000) * PA_USEC_PER_MSEC, &ss);
- uint32_t uvsersion = pa_context_get_protocol_version(pa_ctx);
- if (uvsersion >= RVC_PA_ADJUST_LATENCY_PROTOCOL_VERSION) {
- pastream_flag |= PA_STREAM_ADJUST_LATENCY;
- }
- callback->debug("pa protocol version is %d.", uvsersion);
- }
- else {
- bufattr.fragsize = bufattr.tlength = (uint32_t)-1;
- }
-
- pastream_flag |= PA_STREAM_INTERPOLATE_TIMING;
- pastream_flag |= PA_STREAM_AUTO_TIMING_UPDATE;
- char* dev = audio_ctx->list_input_devices[audio_ctx->device].name;
- callback->debug("AUDIO: (pulse audio) connecting to device %s (channels %d rate %d)",
- dev, ss.channels, ss.rate);
- r = pa_stream_connect_record(recordstream, dev, &bufattr, (pa_stream_flags_t)pastream_flag);
- if (r < 0)
- {
- callback->debug("AUDIO: (pulse audio) skip latency adjustment");
- /*
- * Old pulse audio servers don't like the ADJUST_LATENCY flag,
- * so retry without that
- */
- r = pa_stream_connect_record(recordstream, dev, &bufattr,
- pa_stream_flags_t((int32_t)PA_STREAM_INTERPOLATE_TIMING |
- (int32_t)PA_STREAM_AUTO_TIMING_UPDATE));
- }
- else {
- callback->debug("pa_stream_connect_record success!");
- }
- if (r < 0)
- {
- callback->debug("AUDIO: (pulse audio) pa_stream_connect_record failed");
- finish(pa_ctx, pa_ml);
- return ((void*)-1);
- }
- get_latency(recordstream);
- /*
- * Iterate the main loop while streaming. The second argument is whether
- * or not the iteration should block until something is ready to be
- * done. Set it to zero for non-blocking.
- */
- while (audio_ctx->stream_flag == AUDIO_STRM_ON){
- pa_mainloop_iterate(pa_ml, 1, NULL);
- }
- callback->debug("AUDIO: (pulse audio) stream terminated(%i)", audio_ctx->stream_flag);
- pa_stream_disconnect(recordstream);
- pa_stream_unref(recordstream);
- finish(pa_ctx, pa_ml);
- return ((void*)0);
- }
- int AudioMgrImpl::set_audio_capture_params(audiocap_param_t* param)
- {
- assert(param != NULL);
- audio_set_pulseaudio_device(param->ideviceid);
- audio_set_pulsecap_params(param);
- return 0;
- }
- /*
- * set audio device
- * index - device index to set
- *
- * asserts:
- * audio_ctx is not null
- *
- * returns: none
- */
- int AudioMgrImpl::audio_set_pulseaudio_device(int index)
- {
- /*assertions*/
- assert(m_audio_context != NULL);
- if (index >= m_audio_context->num_input_dev) {
- m_audio_context->device = m_audio_context->num_input_dev - 1;
- }
- else if (index >= 0) {
- m_audio_context->device = index;
- }
-
- int verbosity = 1;
- if (verbosity > 0) {
- printf("AUDIO: Pulseaudio device changed to %i\n", m_audio_context->device);
- printf("AUDIO: Pulseaudio device description is %s\n", m_audio_context->list_input_devices[m_audio_context->device].description);
- }
- m_audio_context->latency = m_audio_context->list_input_devices[m_audio_context->device].high_latency;
- m_audio_context->channels = m_audio_context->list_input_devices[m_audio_context->device].channels;
- if (m_audio_context->channels > 2){
- m_audio_context->channels = 2;/*limit it to stereo input*/
- }
- m_audio_context->samprate = m_audio_context->list_input_devices[m_audio_context->device].samprate;
- return 0;
- }
- int AudioMgrImpl::audio_set_pulsecap_params(audiocap_param_t* param)
- {
- assert(param != NULL);
- m_audio_context->channels = param->ichannels;
- if (m_audio_context->channels > 2) {
- m_audio_context->channels = 2;/*limit it to stereo input*/
- }
- m_audio_context->samprate = param->isamprate;
- m_audio_context->eformat = pa_sample_format_t(param->isampleformat);
- m_audio_context->audio_param.on_audio_callback = param->on_audio_callback;
- m_audio_context->audio_param.user_data = param->user_data;
- m_audio_context->latency = param->flatency;
- //m_audio_context->samprate = m_audio_context->list_input_devices[m_audio_context->device].samprate;
- }
- /*
- * set the current latency
- *
- * asserts:
- * audio_ctx is not null
- *
- * returns: none
- */
- void AudioMgrImpl::audio_set_latency(double latency)
- {
- /*assertions*/
- assert(m_audio_context != NULL);
- m_audio_context->latency = latency;
- }
- rvc_audio_context_t* AudioMgrImpl::audio_get_context()
- {
- return m_audio_context;
- }
- IAudioMgrCallback* AudioMgrImpl::audio_get_callback()
- {
- return m_callback;
- }
- int AudioMgrImpl::start_audio_capture()
- {
- /*assertions*/
- assert(m_audio_context != NULL);
- m_audio_context->stream_flag = AUDIO_STRM_ON;
- //printf("%s:%d stream_flag = %d, audio context is 0x%0x.\n",__FUNCTION__, __LINE__, m_audio_context->stream_flag, m_audio_context);
- /* start audio capture thread */
- if (__THREAD_CREATE(&m_readthread, pulse_read_audio, this)){
- if (m_callback)
- m_callback->debug("AUDIO: (pulse audio) read thread creation failed");
- m_audio_context->stream_flag = AUDIO_STRM_OFF;
- return (-1);
- }
- else {
- if (m_callback)
- m_callback->debug("AUDIO: (pulse audio) read thread creation success, and thread id is %u.", m_readthread);
- }
- return 0;
- }
- int AudioMgrImpl::AudioPulseInit()
- {
- return 0;
- //return (int)m_audio_pulse->Init();
- }
|