source.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2006-2010 Nokia Corporation
  7. * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
  8. * Copyright (C) 2009 Joao Paulo Rechi Vita
  9. *
  10. *
  11. */
  12. #ifdef HAVE_CONFIG_H
  13. #include <config.h>
  14. #endif
  15. #include <stdint.h>
  16. #include <stdbool.h>
  17. #include <errno.h>
  18. #include <glib.h>
  19. #include <dbus/dbus.h>
  20. #include "lib/bluetooth.h"
  21. #include "lib/sdp.h"
  22. #include "gdbus/gdbus.h"
  23. #include "src/log.h"
  24. #include "src/adapter.h"
  25. #include "src/device.h"
  26. #include "src/service.h"
  27. #include "src/error.h"
  28. #include "src/dbus-common.h"
  29. #include "src/shared/queue.h"
  30. #include "avdtp.h"
  31. #include "media.h"
  32. #include "a2dp.h"
  33. #include "source.h"
  34. struct source {
  35. struct btd_service *service;
  36. struct avdtp *session;
  37. struct avdtp_stream *stream;
  38. unsigned int cb_id;
  39. avdtp_session_state_t session_state;
  40. avdtp_state_t stream_state;
  41. source_state_t state;
  42. unsigned int connect_id;
  43. unsigned int disconnect_id;
  44. unsigned int avdtp_callback_id;
  45. };
  46. struct source_state_callback {
  47. source_state_cb cb;
  48. struct btd_service *service;
  49. void *user_data;
  50. unsigned int id;
  51. };
  52. static GSList *source_callbacks = NULL;
  53. static char *str_state[] = {
  54. "SOURCE_STATE_DISCONNECTED",
  55. "SOURCE_STATE_CONNECTING",
  56. "SOURCE_STATE_CONNECTED",
  57. "SOURCE_STATE_PLAYING",
  58. };
  59. static void source_set_state(struct source *source, source_state_t new_state)
  60. {
  61. struct btd_device *dev = btd_service_get_device(source->service);
  62. source_state_t old_state = source->state;
  63. GSList *l;
  64. source->state = new_state;
  65. DBG("State changed %s: %s -> %s", device_get_path(dev),
  66. str_state[old_state], str_state[new_state]);
  67. for (l = source_callbacks; l != NULL; l = l->next) {
  68. struct source_state_callback *cb = l->data;
  69. if (cb->service != source->service)
  70. continue;
  71. cb->cb(source->service, old_state, new_state, cb->user_data);
  72. }
  73. if (new_state != SOURCE_STATE_DISCONNECTED)
  74. return;
  75. if (source->session) {
  76. avdtp_unref(source->session);
  77. source->session = NULL;
  78. }
  79. }
  80. static void avdtp_state_callback(struct btd_device *dev, struct avdtp *session,
  81. avdtp_session_state_t old_state,
  82. avdtp_session_state_t new_state,
  83. void *user_data)
  84. {
  85. struct source *source = user_data;
  86. switch (new_state) {
  87. case AVDTP_SESSION_STATE_DISCONNECTED:
  88. source_set_state(source, SOURCE_STATE_DISCONNECTED);
  89. break;
  90. case AVDTP_SESSION_STATE_CONNECTING:
  91. source_set_state(source, SOURCE_STATE_CONNECTING);
  92. break;
  93. case AVDTP_SESSION_STATE_CONNECTED:
  94. break;
  95. }
  96. source->session_state = new_state;
  97. }
  98. static void stream_state_changed(struct avdtp_stream *stream,
  99. avdtp_state_t old_state,
  100. avdtp_state_t new_state,
  101. struct avdtp_error *err,
  102. void *user_data)
  103. {
  104. struct btd_service *service = user_data;
  105. struct source *source = btd_service_get_user_data(service);
  106. if (err)
  107. return;
  108. switch (new_state) {
  109. case AVDTP_STATE_IDLE:
  110. btd_service_disconnecting_complete(source->service, 0);
  111. if (source->disconnect_id > 0) {
  112. a2dp_cancel(source->disconnect_id);
  113. source->disconnect_id = 0;
  114. }
  115. if (source->session) {
  116. avdtp_unref(source->session);
  117. source->session = NULL;
  118. }
  119. source->stream = NULL;
  120. source->cb_id = 0;
  121. break;
  122. case AVDTP_STATE_OPEN:
  123. btd_service_connecting_complete(source->service, 0);
  124. source_set_state(source, SOURCE_STATE_CONNECTED);
  125. break;
  126. case AVDTP_STATE_STREAMING:
  127. source_set_state(source, SOURCE_STATE_PLAYING);
  128. break;
  129. case AVDTP_STATE_CONFIGURED:
  130. case AVDTP_STATE_CLOSING:
  131. case AVDTP_STATE_ABORTING:
  132. default:
  133. break;
  134. }
  135. source->stream_state = new_state;
  136. }
  137. static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
  138. struct avdtp_stream *stream, int err,
  139. void *user_data)
  140. {
  141. struct source *source = user_data;
  142. source->connect_id = 0;
  143. if (stream)
  144. return;
  145. avdtp_unref(source->session);
  146. source->session = NULL;
  147. btd_service_connecting_complete(source->service, err);
  148. }
  149. static void select_complete(struct avdtp *session, struct a2dp_sep *sep,
  150. GSList *caps, int err, void *user_data)
  151. {
  152. struct source *source = user_data;
  153. int id;
  154. source->connect_id = 0;
  155. if (err)
  156. goto failed;
  157. if (caps == NULL)
  158. goto failed;
  159. id = a2dp_config(session, sep, stream_setup_complete, caps, source);
  160. if (id == 0)
  161. goto failed;
  162. source->connect_id = id;
  163. return;
  164. failed:
  165. btd_service_connecting_complete(source->service, -EIO);
  166. avdtp_unref(source->session);
  167. source->session = NULL;
  168. }
  169. static void discovery_complete(struct avdtp *session, GSList *seps, int err,
  170. void *user_data)
  171. {
  172. struct source *source = user_data;
  173. int id;
  174. source->connect_id = 0;
  175. if (err) {
  176. avdtp_unref(source->session);
  177. source->session = NULL;
  178. goto failed;
  179. }
  180. DBG("Discovery complete");
  181. id = a2dp_select_capabilities(source->session, AVDTP_SEP_TYPE_SOURCE,
  182. NULL, select_complete, source);
  183. if (id == 0) {
  184. err = -EIO;
  185. goto failed;
  186. }
  187. source->connect_id = id;
  188. return;
  189. failed:
  190. btd_service_connecting_complete(source->service, err);
  191. avdtp_unref(source->session);
  192. source->session = NULL;
  193. }
  194. gboolean source_setup_stream(struct btd_service *service,
  195. struct avdtp *session)
  196. {
  197. struct source *source = btd_service_get_user_data(service);
  198. if (source->connect_id > 0 || source->disconnect_id > 0)
  199. return FALSE;
  200. if (!source->session) {
  201. if (session)
  202. source->session = avdtp_ref(session);
  203. else
  204. source->session = a2dp_avdtp_get(
  205. btd_service_get_device(service));
  206. if (!source->session) {
  207. DBG("Unable to get a session");
  208. return FALSE;
  209. }
  210. }
  211. source->connect_id = a2dp_discover(source->session, discovery_complete,
  212. source);
  213. if (source->connect_id == 0) {
  214. avdtp_unref(source->session);
  215. source->session = NULL;
  216. return FALSE;
  217. }
  218. return TRUE;
  219. }
  220. int source_connect(struct btd_service *service)
  221. {
  222. struct source *source = btd_service_get_user_data(service);
  223. if (source->connect_id > 0 || source->disconnect_id > 0)
  224. return -EBUSY;
  225. if (source->state == SOURCE_STATE_CONNECTING)
  226. return -EBUSY;
  227. if (source->stream_state >= AVDTP_STATE_OPEN)
  228. return -EALREADY;
  229. if (!source_setup_stream(service, NULL)) {
  230. DBG("Failed to create a stream");
  231. return -EIO;
  232. }
  233. DBG("stream creation in progress");
  234. return 0;
  235. }
  236. static void source_free(struct btd_service *service)
  237. {
  238. struct source *source = btd_service_get_user_data(service);
  239. if (source->cb_id)
  240. avdtp_stream_remove_cb(source->session, source->stream,
  241. source->cb_id);
  242. if (source->session)
  243. avdtp_unref(source->session);
  244. if (source->connect_id > 0) {
  245. btd_service_connecting_complete(source->service, -ECANCELED);
  246. a2dp_cancel(source->connect_id);
  247. source->connect_id = 0;
  248. }
  249. if (source->disconnect_id > 0) {
  250. btd_service_disconnecting_complete(source->service, -ECANCELED);
  251. a2dp_cancel(source->disconnect_id);
  252. source->disconnect_id = 0;
  253. }
  254. avdtp_remove_state_cb(source->avdtp_callback_id);
  255. btd_service_unref(source->service);
  256. g_free(source);
  257. }
  258. void source_unregister(struct btd_service *service)
  259. {
  260. struct btd_device *dev = btd_service_get_device(service);
  261. DBG("%s", device_get_path(dev));
  262. source_free(service);
  263. }
  264. int source_init(struct btd_service *service)
  265. {
  266. struct btd_device *dev = btd_service_get_device(service);
  267. struct source *source;
  268. DBG("%s", device_get_path(dev));
  269. source = g_new0(struct source, 1);
  270. source->service = btd_service_ref(service);
  271. source->avdtp_callback_id = avdtp_add_state_cb(dev,
  272. avdtp_state_callback,
  273. source);
  274. btd_service_set_user_data(service, source);
  275. return 0;
  276. }
  277. gboolean source_new_stream(struct btd_service *service, struct avdtp *session,
  278. struct avdtp_stream *stream)
  279. {
  280. struct source *source = btd_service_get_user_data(service);
  281. if (source->stream)
  282. return FALSE;
  283. if (!source->session)
  284. source->session = avdtp_ref(session);
  285. source->stream = stream;
  286. source->cb_id = avdtp_stream_add_cb(session, stream,
  287. stream_state_changed, service);
  288. return TRUE;
  289. }
  290. int source_disconnect(struct btd_service *service)
  291. {
  292. struct source *source = btd_service_get_user_data(service);
  293. if (!source->session)
  294. return -ENOTCONN;
  295. /* cancel pending connect */
  296. if (source->connect_id > 0) {
  297. avdtp_unref(source->session);
  298. source->session = NULL;
  299. a2dp_cancel(source->connect_id);
  300. source->connect_id = 0;
  301. btd_service_disconnecting_complete(source->service, 0);
  302. return 0;
  303. }
  304. /* disconnect already ongoing */
  305. if (source->disconnect_id > 0)
  306. return -EBUSY;
  307. if (!source->stream)
  308. return -ENOTCONN;
  309. return avdtp_close(source->session, source->stream, FALSE);
  310. }
  311. unsigned int source_add_state_cb(struct btd_service *service,
  312. source_state_cb cb, void *user_data)
  313. {
  314. struct source_state_callback *state_cb;
  315. static unsigned int id = 0;
  316. state_cb = g_new(struct source_state_callback, 1);
  317. state_cb->cb = cb;
  318. state_cb->service = service;
  319. state_cb->user_data = user_data;
  320. state_cb->id = ++id;
  321. source_callbacks = g_slist_append(source_callbacks, state_cb);
  322. return state_cb->id;
  323. }
  324. gboolean source_remove_state_cb(unsigned int id)
  325. {
  326. GSList *l;
  327. for (l = source_callbacks; l != NULL; l = l->next) {
  328. struct source_state_callback *cb = l->data;
  329. if (cb && cb->id == id) {
  330. source_callbacks = g_slist_remove(source_callbacks, cb);
  331. g_free(cb);
  332. return TRUE;
  333. }
  334. }
  335. return FALSE;
  336. }