1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2008 Lennart Poettering 5 Copyright 2011 Colin Guthrie 6 7 PulseAudio is free software; you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as published 9 by the Free Software Foundation; either version 2.1 of the License, 10 or (at your option) any later version. 11 12 PulseAudio is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 19***/ 20 21#ifdef HAVE_CONFIG_H 22#include <config.h> 23#endif 24 25#include <pulse/context.h> 26#include <pulse/gccmacro.h> 27#include <pulse/xmalloc.h> 28#include <pulse/fork-detect.h> 29#include <pulse/operation.h> 30#include <pulse/format.h> 31 32#include <pulsecore/macro.h> 33#include <pulsecore/pstream-util.h> 34 35#include "internal.h" 36#include "ext-device-restore.h" 37 38/* Protocol extension commands */ 39enum { 40 SUBCOMMAND_TEST, 41 SUBCOMMAND_SUBSCRIBE, 42 SUBCOMMAND_EVENT, 43 SUBCOMMAND_READ_FORMATS_ALL, 44 SUBCOMMAND_READ_FORMATS, 45 SUBCOMMAND_SAVE_FORMATS 46}; 47 48static void ext_device_restore_test_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 49 pa_operation *o = userdata; 50 uint32_t version = PA_INVALID_INDEX; 51 52 pa_assert(pd); 53 pa_assert(o); 54 pa_assert(PA_REFCNT_VALUE(o) >= 1); 55 56 if (!o->context) 57 goto finish; 58 59 if (command != PA_COMMAND_REPLY) { 60 if (pa_context_handle_error(o->context, command, t, false) < 0) 61 goto finish; 62 63 } else if (pa_tagstruct_getu32(t, &version) < 0 || 64 !pa_tagstruct_eof(t)) { 65 66 pa_context_fail(o->context, PA_ERR_PROTOCOL); 67 goto finish; 68 } 69 70 if (o->callback) { 71 pa_ext_device_restore_test_cb_t cb = (pa_ext_device_restore_test_cb_t) o->callback; 72 cb(o->context, version, o->userdata); 73 } 74 75finish: 76 pa_operation_done(o); 77 pa_operation_unref(o); 78} 79 80pa_operation *pa_ext_device_restore_test( 81 pa_context *c, 82 pa_ext_device_restore_test_cb_t cb, 83 void *userdata) { 84 85 uint32_t tag; 86 pa_operation *o; 87 pa_tagstruct *t; 88 89 pa_assert(c); 90 pa_assert(PA_REFCNT_VALUE(c) >= 1); 91 92 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); 93 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); 94 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED); 95 96 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); 97 98 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag); 99 pa_tagstruct_putu32(t, PA_INVALID_INDEX); 100 pa_tagstruct_puts(t, "module-device-restore"); 101 pa_tagstruct_putu32(t, SUBCOMMAND_TEST); 102 pa_pstream_send_tagstruct(c->pstream, t); 103 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_device_restore_test_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 104 105 return o; 106} 107 108pa_operation *pa_ext_device_restore_subscribe( 109 pa_context *c, 110 int enable, 111 pa_context_success_cb_t cb, 112 void *userdata) { 113 114 uint32_t tag; 115 pa_operation *o; 116 pa_tagstruct *t; 117 118 pa_assert(c); 119 pa_assert(PA_REFCNT_VALUE(c) >= 1); 120 121 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); 122 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); 123 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED); 124 125 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); 126 127 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag); 128 pa_tagstruct_putu32(t, PA_INVALID_INDEX); 129 pa_tagstruct_puts(t, "module-device-restore"); 130 pa_tagstruct_putu32(t, SUBCOMMAND_SUBSCRIBE); 131 pa_tagstruct_put_boolean(t, enable); 132 pa_pstream_send_tagstruct(c->pstream, t); 133 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 134 135 return o; 136} 137 138void pa_ext_device_restore_set_subscribe_cb( 139 pa_context *c, 140 pa_ext_device_restore_subscribe_cb_t cb, 141 void *userdata) { 142 143 pa_assert(c); 144 pa_assert(PA_REFCNT_VALUE(c) >= 1); 145 146 if (pa_detect_fork()) 147 return; 148 149 c->ext_device_restore.callback = cb; 150 c->ext_device_restore.userdata = userdata; 151} 152 153static void ext_device_restore_read_device_formats_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 154 pa_operation *o = userdata; 155 int eol = 1; 156 157 pa_assert(pd); 158 pa_assert(o); 159 pa_assert(PA_REFCNT_VALUE(o) >= 1); 160 161 if (!o->context) 162 goto finish; 163 164 if (command != PA_COMMAND_REPLY) { 165 if (pa_context_handle_error(o->context, command, t, false) < 0) 166 goto finish; 167 168 eol = -1; 169 } else { 170 uint8_t j; 171 172 while (!pa_tagstruct_eof(t)) { 173 pa_ext_device_restore_info i; 174 pa_zero(i); 175 176 if (pa_tagstruct_getu32(t, &i.type) < 0 || 177 pa_tagstruct_getu32(t, &i.index) < 0 || 178 pa_tagstruct_getu8(t, &i.n_formats) < 0) { 179 180 pa_context_fail(o->context, PA_ERR_PROTOCOL); 181 goto finish; 182 } 183 184 if (PA_DEVICE_TYPE_SINK != i.type && PA_DEVICE_TYPE_SOURCE != i.type) { 185 pa_context_fail(o->context, PA_ERR_PROTOCOL); 186 goto finish; 187 } 188 189 if (i.index == PA_INVALID_INDEX) { 190 pa_context_fail(o->context, PA_ERR_PROTOCOL); 191 goto finish; 192 } 193 194 if (i.n_formats > 0) { 195 i.formats = pa_xnew0(pa_format_info*, i.n_formats); 196 197 for (j = 0; j < i.n_formats; j++) { 198 199 pa_format_info *f = i.formats[j] = pa_format_info_new(); 200 if (pa_tagstruct_get_format_info(t, f) < 0) { 201 uint8_t k; 202 203 pa_context_fail(o->context, PA_ERR_PROTOCOL); 204 for (k = 0; k < j+1; k++) 205 pa_format_info_free(i.formats[k]); 206 pa_xfree(i.formats); 207 goto finish; 208 } 209 } 210 } 211 212 if (o->callback) { 213 pa_ext_device_restore_read_device_formats_cb_t cb = (pa_ext_device_restore_read_device_formats_cb_t) o->callback; 214 cb(o->context, &i, 0, o->userdata); 215 } 216 217 for (j = 0; j < i.n_formats; j++) 218 pa_format_info_free(i.formats[j]); 219 pa_xfree(i.formats); 220 } 221 } 222 223 if (o->callback) { 224 pa_ext_device_restore_read_device_formats_cb_t cb = (pa_ext_device_restore_read_device_formats_cb_t) o->callback; 225 cb(o->context, NULL, eol, o->userdata); 226 } 227 228finish: 229 pa_operation_done(o); 230 pa_operation_unref(o); 231} 232 233pa_operation *pa_ext_device_restore_read_formats_all( 234 pa_context *c, 235 pa_ext_device_restore_read_device_formats_cb_t cb, 236 void *userdata) { 237 238 uint32_t tag; 239 pa_operation *o; 240 pa_tagstruct *t; 241 242 pa_assert(c); 243 pa_assert(PA_REFCNT_VALUE(c) >= 1); 244 245 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); 246 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); 247 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED); 248 249 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); 250 251 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag); 252 pa_tagstruct_putu32(t, PA_INVALID_INDEX); 253 pa_tagstruct_puts(t, "module-device-restore"); 254 pa_tagstruct_putu32(t, SUBCOMMAND_READ_FORMATS_ALL); 255 pa_pstream_send_tagstruct(c->pstream, t); 256 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_device_restore_read_device_formats_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 257 258 return o; 259} 260 261pa_operation *pa_ext_device_restore_read_formats( 262 pa_context *c, 263 pa_device_type_t type, 264 uint32_t idx, 265 pa_ext_device_restore_read_device_formats_cb_t cb, 266 void *userdata) { 267 268 uint32_t tag; 269 pa_operation *o; 270 pa_tagstruct *t; 271 272 pa_assert(c); 273 pa_assert(PA_REFCNT_VALUE(c) >= 1); 274 pa_assert(idx != PA_INVALID_INDEX); 275 276 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); 277 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); 278 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED); 279 280 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); 281 282 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag); 283 pa_tagstruct_putu32(t, PA_INVALID_INDEX); 284 pa_tagstruct_puts(t, "module-device-restore"); 285 pa_tagstruct_putu32(t, SUBCOMMAND_READ_FORMATS); 286 pa_tagstruct_putu32(t, type); 287 pa_tagstruct_putu32(t, idx); 288 pa_pstream_send_tagstruct(c->pstream, t); 289 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_device_restore_read_device_formats_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 290 291 return o; 292} 293 294pa_operation *pa_ext_device_restore_save_formats( 295 pa_context *c, 296 pa_device_type_t type, 297 uint32_t idx, 298 uint8_t n_formats, 299 pa_format_info **formats, 300 pa_context_success_cb_t cb, 301 void *userdata) { 302 303 uint32_t tag; 304 pa_operation *o; 305 pa_tagstruct *t; 306 uint8_t j; 307 308 pa_assert(c); 309 pa_assert(PA_REFCNT_VALUE(c) >= 1); 310 pa_assert(idx != PA_INVALID_INDEX); 311 pa_assert(n_formats > 0); 312 pa_assert(formats && *formats); 313 314 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); 315 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); 316 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED); 317 318 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); 319 320 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag); 321 pa_tagstruct_putu32(t, PA_INVALID_INDEX); 322 pa_tagstruct_puts(t, "module-device-restore"); 323 pa_tagstruct_putu32(t, SUBCOMMAND_SAVE_FORMATS); 324 325 pa_tagstruct_putu32(t, type); 326 pa_tagstruct_putu32(t, idx); 327 pa_tagstruct_putu8(t, n_formats); 328 for (j = 0; j < n_formats; j++) 329 pa_tagstruct_put_format_info(t, formats[j]); 330 331 pa_pstream_send_tagstruct(c->pstream, t); 332 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 333 334 return o; 335} 336 337/* Command function defined in internal.h */ 338void pa_ext_device_restore_command(pa_context *c, uint32_t tag, pa_tagstruct *t) { 339 uint32_t subcommand; 340 pa_device_type_t type; 341 uint32_t idx; 342 343 pa_assert(c); 344 pa_assert(PA_REFCNT_VALUE(c) >= 1); 345 pa_assert(t); 346 347 if (pa_tagstruct_getu32(t, &subcommand) < 0 || 348 pa_tagstruct_getu32(t, &type) < 0 || 349 pa_tagstruct_getu32(t, &idx) < 0 || 350 !pa_tagstruct_eof(t)) { 351 352 pa_context_fail(c, PA_ERR_PROTOCOL); 353 return; 354 } 355 356 if (subcommand != SUBCOMMAND_EVENT) { 357 pa_context_fail(c, PA_ERR_PROTOCOL); 358 return; 359 } 360 361 if (PA_DEVICE_TYPE_SINK != type && PA_DEVICE_TYPE_SOURCE != type) { 362 pa_context_fail(c, PA_ERR_PROTOCOL); 363 return; 364 } 365 366 if (idx == PA_INVALID_INDEX) { 367 pa_context_fail(c, PA_ERR_PROTOCOL); 368 return; 369 } 370 371 if (c->ext_device_restore.callback) 372 c->ext_device_restore.callback(c, type, idx, c->ext_device_restore.userdata); 373} 374