LCOV - code coverage report
Current view: top level - media/libcubeb/src - cubeb.c (source / functions) Hit Total Coverage
Test: output.info Lines: 8 228 3.5 %
Date: 2017-07-14 16:53:18 Functions: 1 25 4.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright © 2013 Mozilla Foundation
       3             :  *
       4             :  * This program is made available under an ISC-style license.  See the
       5             :  * accompanying file LICENSE for details.
       6             :  */
       7             : #undef NDEBUG
       8             : #include <assert.h>
       9             : #include <stddef.h>
      10             : #include <stdlib.h>
      11             : #include <string.h>
      12             : #include "cubeb/cubeb.h"
      13             : #include "cubeb-internal.h"
      14             : 
      15             : #define NELEMS(x) ((int) (sizeof(x) / sizeof(x[0])))
      16             : 
      17             : struct cubeb {
      18             :   struct cubeb_ops * ops;
      19             : };
      20             : 
      21             : struct cubeb_stream {
      22             :   struct cubeb * context;
      23             : };
      24             : 
      25             : #if defined(USE_PULSE)
      26             : int pulse_init(cubeb ** context, char const * context_name);
      27             : #endif
      28             : #if defined(USE_PULSE_RUST)
      29             : int pulse_rust_init(cubeb ** contet, char const * context_name);
      30             : #endif
      31             : #if defined(USE_JACK)
      32             : int jack_init (cubeb ** context, char const * context_name);
      33             : #endif
      34             : #if defined(USE_ALSA)
      35             : int alsa_init(cubeb ** context, char const * context_name);
      36             : #endif
      37             : #if defined(USE_AUDIOUNIT)
      38             : int audiounit_init(cubeb ** context, char const * context_name);
      39             : #endif
      40             : #if defined(USE_WINMM)
      41             : int winmm_init(cubeb ** context, char const * context_name);
      42             : #endif
      43             : #if defined(USE_WASAPI)
      44             : int wasapi_init(cubeb ** context, char const * context_name);
      45             : #endif
      46             : #if defined(USE_SNDIO)
      47             : int sndio_init(cubeb ** context, char const * context_name);
      48             : #endif
      49             : #if defined(USE_OPENSL)
      50             : int opensl_init(cubeb ** context, char const * context_name);
      51             : #endif
      52             : #if defined(USE_AUDIOTRACK)
      53             : int audiotrack_init(cubeb ** context, char const * context_name);
      54             : #endif
      55             : #if defined(USE_KAI)
      56             : int kai_init(cubeb ** context, char const * context_name);
      57             : #endif
      58             : 
      59             : static int
      60           0 : validate_stream_params(cubeb_stream_params * input_stream_params,
      61             :                        cubeb_stream_params * output_stream_params)
      62             : {
      63           0 :   XASSERT(input_stream_params || output_stream_params);
      64           0 :   if (output_stream_params) {
      65           0 :     if (output_stream_params->rate < 1000 || output_stream_params->rate > 192000 ||
      66           0 :         output_stream_params->channels < 1 || output_stream_params->channels > 8) {
      67           0 :       return CUBEB_ERROR_INVALID_FORMAT;
      68             :     }
      69             :   }
      70           0 :   if (input_stream_params) {
      71           0 :     if (input_stream_params->rate < 1000 || input_stream_params->rate > 192000 ||
      72           0 :         input_stream_params->channels < 1 || input_stream_params->channels > 8) {
      73           0 :       return CUBEB_ERROR_INVALID_FORMAT;
      74             :     }
      75             :   }
      76             :   // Rate and sample format must be the same for input and output, if using a
      77             :   // duplex stream
      78           0 :   if (input_stream_params && output_stream_params) {
      79           0 :     if (input_stream_params->rate != output_stream_params->rate  ||
      80           0 :         input_stream_params->format != output_stream_params->format) {
      81           0 :       return CUBEB_ERROR_INVALID_FORMAT;
      82             :     }
      83             :   }
      84             : 
      85           0 :   cubeb_stream_params * params = input_stream_params ?
      86           0 :                                  input_stream_params : output_stream_params;
      87             : 
      88           0 :   switch (params->format) {
      89             :   case CUBEB_SAMPLE_S16LE:
      90             :   case CUBEB_SAMPLE_S16BE:
      91             :   case CUBEB_SAMPLE_FLOAT32LE:
      92             :   case CUBEB_SAMPLE_FLOAT32BE:
      93           0 :     return CUBEB_OK;
      94             :   }
      95             : 
      96           0 :   return CUBEB_ERROR_INVALID_FORMAT;
      97             : }
      98             : 
      99             : static int
     100           0 : validate_latency(int latency)
     101             : {
     102           0 :   if (latency < 1 || latency > 96000) {
     103           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     104             :   }
     105           0 :   return CUBEB_OK;
     106             : }
     107             : 
     108             : int
     109           0 : cubeb_init(cubeb ** context, char const * context_name, char const * backend_name)
     110             : {
     111           0 :   int (* init_oneshot)(cubeb **, char const *) = NULL;
     112             : 
     113           0 :   if (backend_name != NULL) {
     114           0 :     if (!strcmp(backend_name, "pulse")) {
     115             : #if defined(USE_PULSE)
     116           0 :       init_oneshot = pulse_init;
     117             : #endif
     118           0 :     } else if (!strcmp(backend_name, "pulse-rust")) {
     119             : #if defined(USE_PULSE_RUST)
     120           0 :       init_oneshot = pulse_rust_init;
     121             : #endif
     122           0 :     } else if (!strcmp(backend_name, "jack")) {
     123             : #if defined(USE_JACK)
     124             :       init_oneshot = jack_init;
     125             : #endif
     126           0 :     } else if (!strcmp(backend_name, "alsa")) {
     127             : #if defined(USE_ALSA)
     128             :       init_oneshot = alsa_init;
     129             : #endif
     130           0 :     } else if (!strcmp(backend_name, "audiounit")) {
     131             : #if defined(USE_AUDIOUNIT)
     132             :       init_oneshot = audiounit_init;
     133             : #endif
     134           0 :     } else if (!strcmp(backend_name, "wasapi")) {
     135             : #if defined(USE_WASAPI)
     136             :       init_oneshot = wasapi_init;
     137             : #endif
     138           0 :     } else if (!strcmp(backend_name, "winmm")) {
     139             : #if defined(USE_WINMM)
     140             :       init_oneshot = winmm_init;
     141             : #endif
     142           0 :     } else if (!strcmp(backend_name, "sndio")) {
     143             : #if defined(USE_SNDIO)
     144             :       init_oneshot = sndio_init;
     145             : #endif
     146           0 :     } else if (!strcmp(backend_name, "opensl")) {
     147             : #if defined(USE_OPENSL)
     148             :       init_oneshot = opensl_init;
     149             : #endif
     150           0 :     } else if (!strcmp(backend_name, "audiotrack")) {
     151             : #if defined(USE_AUDIOTRACK)
     152             :       init_oneshot = audiotrack_init;
     153             : #endif
     154           0 :     } else if (!strcmp(backend_name, "kai")) {
     155             : #if defined(USE_KAI)
     156             :       init_oneshot = kai_init;
     157             : #endif
     158             :     } else {
     159             :       /* Already set */
     160             :     }
     161             :   }
     162             : 
     163           0 :   int (* default_init[])(cubeb **, char const *) = {
     164             :     /*
     165             :      * init_oneshot must be at the top to allow user
     166             :      * to override all other choices
     167             :      */
     168             :     init_oneshot,
     169             : #if defined(NIGHTLY_BUILD) && defined(USE_PULSE_RUST)
     170             :     pulse_rust_init,
     171             : #endif
     172             : #if defined(USE_PULSE)
     173             :     pulse_init,
     174             : #endif
     175             : #if defined(USE_JACK)
     176             :     jack_init,
     177             : #endif
     178             : #if defined(USE_ALSA)
     179             :     alsa_init,
     180             : #endif
     181             : #if defined(USE_AUDIOUNIT)
     182             :     audiounit_init,
     183             : #endif
     184             : #if defined(USE_WASAPI)
     185             :     wasapi_init,
     186             : #endif
     187             : #if defined(USE_WINMM)
     188             :     winmm_init,
     189             : #endif
     190             : #if defined(USE_SNDIO)
     191             :     sndio_init,
     192             : #endif
     193             : #if defined(USE_OPENSL)
     194             :     opensl_init,
     195             : #endif
     196             : #if defined(USE_AUDIOTRACK)
     197             :     audiotrack_init,
     198             : #endif
     199             : #if defined(USE_KAI)
     200             :     kai_init,
     201             : #endif
     202             :   };
     203             :   int i;
     204             : 
     205           0 :   if (!context) {
     206           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     207             :   }
     208             : 
     209             : #define OK(fn) assert((* context)->ops->fn)
     210           0 :   for (i = 0; i < NELEMS(default_init); ++i) {
     211           0 :     if (default_init[i] && default_init[i](context, context_name) == CUBEB_OK) {
     212             :       /* Assert that the minimal API is implemented. */
     213           0 :       OK(get_backend_id);
     214           0 :       OK(destroy);
     215           0 :       OK(stream_init);
     216           0 :       OK(stream_destroy);
     217           0 :       OK(stream_start);
     218           0 :       OK(stream_stop);
     219           0 :       OK(stream_get_position);
     220           0 :       return CUBEB_OK;
     221             :     }
     222             :   }
     223           0 :   return CUBEB_ERROR;
     224             : }
     225             : 
     226             : char const *
     227           0 : cubeb_get_backend_id(cubeb * context)
     228             : {
     229           0 :   if (!context) {
     230           0 :     return NULL;
     231             :   }
     232             : 
     233           0 :   return context->ops->get_backend_id(context);
     234             : }
     235             : 
     236             : int
     237           0 : cubeb_get_max_channel_count(cubeb * context, uint32_t * max_channels)
     238             : {
     239           0 :   if (!context || !max_channels) {
     240           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     241             :   }
     242             : 
     243           0 :   if (!context->ops->get_max_channel_count) {
     244           0 :     return CUBEB_ERROR_NOT_SUPPORTED;
     245             :   }
     246             : 
     247           0 :   return context->ops->get_max_channel_count(context, max_channels);
     248             : }
     249             : 
     250             : int
     251           0 : cubeb_get_min_latency(cubeb * context, cubeb_stream_params params, uint32_t * latency_ms)
     252             : {
     253           0 :   if (!context || !latency_ms) {
     254           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     255             :   }
     256             : 
     257           0 :   if (!context->ops->get_min_latency) {
     258           0 :     return CUBEB_ERROR_NOT_SUPPORTED;
     259             :   }
     260             : 
     261           0 :   return context->ops->get_min_latency(context, params, latency_ms);
     262             : }
     263             : 
     264             : int
     265           0 : cubeb_get_preferred_sample_rate(cubeb * context, uint32_t * rate)
     266             : {
     267           0 :   if (!context || !rate) {
     268           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     269             :   }
     270             : 
     271           0 :   if (!context->ops->get_preferred_sample_rate) {
     272           0 :     return CUBEB_ERROR_NOT_SUPPORTED;
     273             :   }
     274             : 
     275           0 :   return context->ops->get_preferred_sample_rate(context, rate);
     276             : }
     277             : 
     278             : int
     279           0 : cubeb_get_preferred_channel_layout(cubeb * context, cubeb_channel_layout * layout)
     280             : {
     281           0 :   if (!context || !layout) {
     282           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     283             :   }
     284             : 
     285           0 :   if (!context->ops->get_preferred_channel_layout) {
     286           0 :     return CUBEB_ERROR_NOT_SUPPORTED;
     287             :   }
     288             : 
     289           0 :   return context->ops->get_preferred_channel_layout(context, layout);
     290             : }
     291             : 
     292             : void
     293           0 : cubeb_destroy(cubeb * context)
     294             : {
     295           0 :   if (!context) {
     296           0 :     return;
     297             :   }
     298             : 
     299           0 :   context->ops->destroy(context);
     300             : }
     301             : 
     302             : int
     303           0 : cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name,
     304             :                   cubeb_devid input_device,
     305             :                   cubeb_stream_params * input_stream_params,
     306             :                   cubeb_devid output_device,
     307             :                   cubeb_stream_params * output_stream_params,
     308             :                   unsigned int latency,
     309             :                   cubeb_data_callback data_callback,
     310             :                   cubeb_state_callback state_callback,
     311             :                   void * user_ptr)
     312             : {
     313             :   int r;
     314             : 
     315           0 :   if (!context || !stream) {
     316           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     317             :   }
     318             : 
     319           0 :   if ((r = validate_stream_params(input_stream_params, output_stream_params)) != CUBEB_OK ||
     320           0 :       (r = validate_latency(latency)) != CUBEB_OK) {
     321           0 :     return r;
     322             :   }
     323             : 
     324           0 :   r = context->ops->stream_init(context, stream, stream_name,
     325             :                                 input_device,
     326             :                                 input_stream_params,
     327             :                                 output_device,
     328             :                                 output_stream_params,
     329             :                                 latency,
     330             :                                 data_callback,
     331             :                                 state_callback,
     332             :                                 user_ptr);
     333             : 
     334           0 :   if (r == CUBEB_ERROR_INVALID_FORMAT) {
     335           0 :     LOG("Invalid format, %p %p %d %d",
     336             :         output_stream_params, input_stream_params,
     337             :         output_stream_params && output_stream_params->format,
     338             :         input_stream_params && input_stream_params->format);
     339             :   }
     340             : 
     341           0 :   return r;
     342             : }
     343             : 
     344             : void
     345           0 : cubeb_stream_destroy(cubeb_stream * stream)
     346             : {
     347           0 :   if (!stream) {
     348           0 :     return;
     349             :   }
     350             : 
     351           0 :   stream->context->ops->stream_destroy(stream);
     352             : }
     353             : 
     354             : int
     355           0 : cubeb_stream_start(cubeb_stream * stream)
     356             : {
     357           0 :   if (!stream) {
     358           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     359             :   }
     360             : 
     361           0 :   return stream->context->ops->stream_start(stream);
     362             : }
     363             : 
     364             : int
     365           0 : cubeb_stream_stop(cubeb_stream * stream)
     366             : {
     367           0 :   if (!stream) {
     368           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     369             :   }
     370             : 
     371           0 :   return stream->context->ops->stream_stop(stream);
     372             : }
     373             : 
     374             : int
     375           0 : cubeb_stream_get_position(cubeb_stream * stream, uint64_t * position)
     376             : {
     377           0 :   if (!stream || !position) {
     378           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     379             :   }
     380             : 
     381           0 :   return stream->context->ops->stream_get_position(stream, position);
     382             : }
     383             : 
     384             : int
     385           0 : cubeb_stream_get_latency(cubeb_stream * stream, uint32_t * latency)
     386             : {
     387           0 :   if (!stream || !latency) {
     388           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     389             :   }
     390             : 
     391           0 :   if (!stream->context->ops->stream_get_latency) {
     392           0 :     return CUBEB_ERROR_NOT_SUPPORTED;
     393             :   }
     394             : 
     395           0 :   return stream->context->ops->stream_get_latency(stream, latency);
     396             : }
     397             : 
     398             : int
     399           0 : cubeb_stream_set_volume(cubeb_stream * stream, float volume)
     400             : {
     401           0 :   if (!stream || volume > 1.0 || volume < 0.0) {
     402           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     403             :   }
     404             : 
     405           0 :   if (!stream->context->ops->stream_set_volume) {
     406           0 :     return CUBEB_ERROR_NOT_SUPPORTED;
     407             :   }
     408             : 
     409           0 :   return stream->context->ops->stream_set_volume(stream, volume);
     410             : }
     411             : 
     412           0 : int cubeb_stream_set_panning(cubeb_stream * stream, float panning)
     413             : {
     414           0 :   if (!stream || panning < -1.0 || panning > 1.0) {
     415           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     416             :   }
     417             : 
     418           0 :   if (!stream->context->ops->stream_set_panning) {
     419           0 :     return CUBEB_ERROR_NOT_SUPPORTED;
     420             :   }
     421             : 
     422           0 :   return stream->context->ops->stream_set_panning(stream, panning);
     423             : }
     424             : 
     425           0 : int cubeb_stream_get_current_device(cubeb_stream * stream,
     426             :                                     cubeb_device ** const device)
     427             : {
     428           0 :   if (!stream || !device) {
     429           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     430             :   }
     431             : 
     432           0 :   if (!stream->context->ops->stream_get_current_device) {
     433           0 :     return CUBEB_ERROR_NOT_SUPPORTED;
     434             :   }
     435             : 
     436           0 :   return stream->context->ops->stream_get_current_device(stream, device);
     437             : }
     438             : 
     439           0 : int cubeb_stream_device_destroy(cubeb_stream * stream,
     440             :                                 cubeb_device * device)
     441             : {
     442           0 :   if (!stream || !device) {
     443           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     444             :   }
     445             : 
     446           0 :   if (!stream->context->ops->stream_device_destroy) {
     447           0 :     return CUBEB_ERROR_NOT_SUPPORTED;
     448             :   }
     449             : 
     450           0 :   return stream->context->ops->stream_device_destroy(stream, device);
     451             : }
     452             : 
     453           0 : int cubeb_stream_register_device_changed_callback(cubeb_stream * stream,
     454             :                                                   cubeb_device_changed_callback device_changed_callback)
     455             : {
     456           0 :   if (!stream) {
     457           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     458             :   }
     459             : 
     460           0 :   if (!stream->context->ops->stream_register_device_changed_callback) {
     461           0 :     return CUBEB_ERROR_NOT_SUPPORTED;
     462             :   }
     463             : 
     464           0 :   return stream->context->ops->stream_register_device_changed_callback(stream, device_changed_callback);
     465             : }
     466             : 
     467             : static
     468           0 : void log_device(cubeb_device_info * device_info)
     469             : {
     470           0 :   char devfmts[128] = "";
     471             :   const char * devtype, * devstate, * devdeffmt;
     472             : 
     473           0 :   switch (device_info->type) {
     474             :     case CUBEB_DEVICE_TYPE_INPUT:
     475           0 :       devtype = "input";
     476           0 :       break;
     477             :     case CUBEB_DEVICE_TYPE_OUTPUT:
     478           0 :       devtype = "output";
     479           0 :       break;
     480             :     case CUBEB_DEVICE_TYPE_UNKNOWN:
     481             :     default:
     482           0 :       devtype = "unknown?";
     483           0 :       break;
     484             :   };
     485             : 
     486           0 :   switch (device_info->state) {
     487             :     case CUBEB_DEVICE_STATE_DISABLED:
     488           0 :       devstate = "disabled";
     489           0 :       break;
     490             :     case CUBEB_DEVICE_STATE_UNPLUGGED:
     491           0 :       devstate = "unplugged";
     492           0 :       break;
     493             :     case CUBEB_DEVICE_STATE_ENABLED:
     494           0 :       devstate = "enabled";
     495           0 :       break;
     496             :     default:
     497           0 :       devstate = "unknown?";
     498           0 :       break;
     499             :   };
     500             : 
     501           0 :   switch (device_info->default_format) {
     502             :     case CUBEB_DEVICE_FMT_S16LE:
     503           0 :       devdeffmt = "S16LE";
     504           0 :       break;
     505             :     case CUBEB_DEVICE_FMT_S16BE:
     506           0 :       devdeffmt = "S16BE";
     507           0 :       break;
     508             :     case CUBEB_DEVICE_FMT_F32LE:
     509           0 :       devdeffmt = "F32LE";
     510           0 :       break;
     511             :     case CUBEB_DEVICE_FMT_F32BE:
     512           0 :       devdeffmt = "F32BE";
     513           0 :       break;
     514             :     default:
     515           0 :       devdeffmt = "unknown?";
     516           0 :       break;
     517             :   };
     518             : 
     519           0 :   if (device_info->format & CUBEB_DEVICE_FMT_S16LE) {
     520           0 :     strcat(devfmts, " S16LE");
     521             :   }
     522           0 :   if (device_info->format & CUBEB_DEVICE_FMT_S16BE) {
     523           0 :     strcat(devfmts, " S16BE");
     524             :   }
     525           0 :   if (device_info->format & CUBEB_DEVICE_FMT_F32LE) {
     526           0 :     strcat(devfmts, " F32LE");
     527             :   }
     528           0 :   if (device_info->format & CUBEB_DEVICE_FMT_F32BE) {
     529           0 :     strcat(devfmts, " F32BE");
     530             :   }
     531             : 
     532           0 :   LOG("DeviceID: \"%s\"%s\n"
     533             :       "\tName:\t\"%s\"\n"
     534             :       "\tGroup:\t\"%s\"\n"
     535             :       "\tVendor:\t\"%s\"\n"
     536             :       "\tType:\t%s\n"
     537             :       "\tState:\t%s\n"
     538             :       "\tMaximum channels:\t%u\n"
     539             :       "\tFormat:\t%s (0x%x) (default: %s)\n"
     540             :       "\tRate:\t[%u, %u] (default: %u)\n"
     541             :       "\tLatency: lo %u frames, hi %u frames",
     542             :       device_info->device_id, device_info->preferred ? " (PREFERRED)" : "",
     543             :       device_info->friendly_name,
     544             :       device_info->group_id,
     545             :       device_info->vendor_name,
     546             :       devtype,
     547             :       devstate,
     548             :       device_info->max_channels,
     549             :       (devfmts[0] == '\0') ? devfmts : devfmts + 1, (unsigned int)device_info->format, devdeffmt,
     550             :       device_info->min_rate, device_info->max_rate, device_info->default_rate,
     551             :       device_info->latency_lo, device_info->latency_hi);
     552           0 : }
     553             : 
     554           0 : int cubeb_enumerate_devices(cubeb * context,
     555             :                             cubeb_device_type devtype,
     556             :                             cubeb_device_collection * collection)
     557             : {
     558             :   int rv;
     559           0 :   if ((devtype & (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_OUTPUT)) == 0)
     560           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     561           0 :   if (collection == NULL)
     562           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     563           0 :   if (!context->ops->enumerate_devices)
     564           0 :     return CUBEB_ERROR_NOT_SUPPORTED;
     565             : 
     566           0 :   rv = context->ops->enumerate_devices(context, devtype, collection);
     567             : 
     568           0 :   if (g_cubeb_log_callback) {
     569           0 :     for (size_t i = 0; i < collection->count; i++) {
     570           0 :       log_device(&collection->device[i]);
     571             :     }
     572             :   }
     573             : 
     574           0 :   return rv;
     575             : }
     576             : 
     577           0 : int cubeb_device_collection_destroy(cubeb * context,
     578             :                                     cubeb_device_collection * collection)
     579             : {
     580             :   int r;
     581             : 
     582           0 :   if (context == NULL || collection == NULL)
     583           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     584             : 
     585           0 :   if (!context->ops->device_collection_destroy)
     586           0 :     return CUBEB_ERROR_NOT_SUPPORTED;
     587             : 
     588           0 :   if (!collection->device)
     589           0 :     return CUBEB_OK;
     590             : 
     591           0 :   r = context->ops->device_collection_destroy(context, collection);
     592           0 :   if (r == CUBEB_OK) {
     593           0 :     collection->device = NULL;
     594           0 :     collection->count = 0;
     595             :   }
     596             : 
     597           0 :   return r;
     598             : }
     599             : 
     600           0 : int cubeb_register_device_collection_changed(cubeb * context,
     601             :                                              cubeb_device_type devtype,
     602             :                                              cubeb_device_collection_changed_callback callback,
     603             :                                              void * user_ptr)
     604             : {
     605           0 :   if (context == NULL || (devtype & (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_OUTPUT)) == 0)
     606           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     607             : 
     608           0 :   if (!context->ops->register_device_collection_changed) {
     609           0 :     return CUBEB_ERROR_NOT_SUPPORTED;
     610             :   }
     611             : 
     612           0 :   return context->ops->register_device_collection_changed(context, devtype, callback, user_ptr);
     613             : }
     614             : 
     615           3 : int cubeb_set_log_callback(cubeb_log_level log_level,
     616             :                            cubeb_log_callback log_callback)
     617             : {
     618           3 :   if (log_level < CUBEB_LOG_DISABLED || log_level > CUBEB_LOG_VERBOSE) {
     619           0 :     return CUBEB_ERROR_INVALID_FORMAT;
     620             :   }
     621             : 
     622           3 :   if (!log_callback && log_level != CUBEB_LOG_DISABLED) {
     623           0 :     return CUBEB_ERROR_INVALID_PARAMETER;
     624             :   }
     625             : 
     626           3 :   if (g_cubeb_log_callback && log_callback) {
     627           0 :     return CUBEB_ERROR_NOT_SUPPORTED;
     628             :   }
     629             : 
     630           3 :   g_cubeb_log_callback = log_callback;
     631           3 :   g_cubeb_log_level = log_level;
     632             : 
     633             :   // Logging a message here allows to initialize the asynchronous logger from a
     634             :   // thread that is not the audio rendering thread, and especially to not
     635             :   // initialize it the first time we find a verbose log, which is often in the
     636             :   // audio rendering callback, that runs from the audio rendering thread, and
     637             :   // that is high priority, and that we don't want to block.
     638           3 :   if (log_level >= CUBEB_LOG_VERBOSE) {
     639           0 :     ALOGV("Starting cubeb log");
     640             :   }
     641             : 
     642           3 :   return CUBEB_OK;
     643             : }
     644             : 

Generated by: LCOV version 1.13