gstdspdummy.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. /*
  2. * Copyright (C) 2009-2010 Nokia Corporation
  3. *
  4. * Author: Felipe Contreras <felipe.contreras@nokia.com>
  5. *
  6. * This file may be used under the terms of the GNU Lesser General Public
  7. * License version 2.1, a copy of which is found in LICENSE included in the
  8. * packaging of this file.
  9. */
  10. #include "gstdspdummy.h"
  11. #include "plugin.h"
  12. #include "util.h"
  13. #include "dsp_bridge.h"
  14. #include <string.h> /* for memcpy */
  15. #define GST_CAT_DEFAULT gstdsp_debug
  16. static GstElementClass *parent_class;
  17. static GstCaps *
  18. generate_src_template(void)
  19. {
  20. GstCaps *caps;
  21. caps = gst_caps_new_any();
  22. return caps;
  23. }
  24. static GstCaps *
  25. generate_sink_template(void)
  26. {
  27. GstCaps *caps;
  28. caps = gst_caps_new_any();
  29. return caps;
  30. }
  31. static inline void *
  32. create_node(GstDspDummy *self)
  33. {
  34. int dsp_handle = self->dsp_handle;
  35. void *proc = self->proc;
  36. struct dsp_node *node;
  37. const struct dsp_uuid dummy_uuid = { 0x3dac26d0, 0x6d4b, 0x11dd, 0xad, 0x8b,
  38. { 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } };
  39. if (!gstdsp_register(dsp_handle, &dummy_uuid, DSP_DCD_NODETYPE, "test.dll64P")) {
  40. pr_err(self, "dsp node register failed");
  41. return NULL;
  42. }
  43. if (!gstdsp_register(dsp_handle, &dummy_uuid, DSP_DCD_LIBRARYTYPE, "test.dll64P")) {
  44. pr_err(self, "dsp node register failed");
  45. return NULL;
  46. }
  47. if (!dsp_node_allocate(dsp_handle, proc, &dummy_uuid, NULL, NULL, &node)) {
  48. pr_err(self, "dsp node allocate failed");
  49. return NULL;
  50. }
  51. if (!dsp_node_create(dsp_handle, node)) {
  52. pr_err(self, "dsp node create failed");
  53. return NULL;
  54. }
  55. pr_info(self, "dsp node created");
  56. return node;
  57. }
  58. static inline bool
  59. destroy_node(GstDspDummy *self)
  60. {
  61. if (self->node) {
  62. if (!dsp_node_free(self->dsp_handle, self->node)) {
  63. pr_err(self, "dsp node free failed");
  64. return false;
  65. }
  66. pr_info(self, "dsp node deleted");
  67. }
  68. return true;
  69. }
  70. static gboolean
  71. dsp_init(GstDspDummy *self)
  72. {
  73. int dsp_handle;
  74. self->dsp_handle = dsp_handle = dsp_open();
  75. if (dsp_handle < 0) {
  76. pr_err(self, "dsp open failed");
  77. return FALSE;
  78. }
  79. if (!dsp_attach(dsp_handle, 0, NULL, &self->proc)) {
  80. pr_err(self, "dsp attach failed");
  81. goto fail;
  82. }
  83. self->node = create_node(self);
  84. if (!self->node) {
  85. pr_err(self, "dsp node creation failed");
  86. goto fail;
  87. }
  88. return TRUE;
  89. fail:
  90. if (self->proc) {
  91. if (!dsp_detach(dsp_handle, self->proc))
  92. pr_err(self, "dsp detach failed");
  93. self->proc = NULL;
  94. }
  95. if (self->dsp_handle >= 0) {
  96. if (dsp_close(dsp_handle) < 0)
  97. pr_err(self, "dsp close failed");
  98. self->dsp_handle = -1;
  99. }
  100. return FALSE;
  101. }
  102. static gboolean
  103. dsp_deinit(GstDspDummy *self)
  104. {
  105. gboolean ret = TRUE;
  106. if (self->dsp_error)
  107. goto leave;
  108. if (self->proc) {
  109. if (!dsp_detach(self->dsp_handle, self->proc)) {
  110. pr_err(self, "dsp detach failed");
  111. ret = FALSE;
  112. }
  113. self->proc = NULL;
  114. }
  115. leave:
  116. if (self->dsp_handle >= 0) {
  117. if (dsp_close(self->dsp_handle) < 0) {
  118. pr_err(self, "dsp close failed");
  119. ret = FALSE;
  120. }
  121. self->dsp_handle = -1;
  122. }
  123. return ret;
  124. }
  125. static inline void
  126. configure_dsp_node(int dsp_handle,
  127. struct dsp_node *node,
  128. dmm_buffer_t *input_buffer,
  129. dmm_buffer_t *output_buffer)
  130. {
  131. dsp_send_message(dsp_handle, node, 0,
  132. (uint32_t) input_buffer->map,
  133. (uint32_t) output_buffer->map);
  134. }
  135. static gboolean
  136. _dsp_start(GstDspDummy *self)
  137. {
  138. if (!dsp_node_run(self->dsp_handle, self->node)) {
  139. pr_err(self, "dsp node run failed");
  140. return FALSE;
  141. }
  142. pr_info(self, "dsp node running");
  143. self->in_buffer = dmm_buffer_new(self->dsp_handle, self->proc, DMA_TO_DEVICE);
  144. self->out_buffer = dmm_buffer_new(self->dsp_handle, self->proc, DMA_FROM_DEVICE);
  145. self->events[0] = calloc(1, sizeof(struct dsp_notification));
  146. if (!dsp_node_register_notify(self->dsp_handle, self->node,
  147. DSP_NODEMESSAGEREADY, 1,
  148. self->events[0]))
  149. {
  150. pr_err(self, "failed to register for notifications");
  151. return false;
  152. }
  153. self->events[1] = calloc(1, sizeof(struct dsp_notification));
  154. if (!dsp_register_notify(self->dsp_handle, self->proc,
  155. DSP_MMUFAULT, 1,
  156. self->events[1]))
  157. {
  158. pr_err(self, "failed to register for DSP_MMUFAULT");
  159. return false;
  160. }
  161. self->events[2] = calloc(1, sizeof(struct dsp_notification));
  162. if (!dsp_register_notify(self->dsp_handle, self->proc,
  163. DSP_SYSERROR, 1,
  164. self->events[2]))
  165. {
  166. pr_err(self, "failed to register for DSP_SYSERROR");
  167. return false;
  168. }
  169. return TRUE;
  170. }
  171. static gboolean
  172. _dsp_stop(GstDspDummy *self)
  173. {
  174. unsigned long exit_status;
  175. unsigned i;
  176. dmm_buffer_free(self->out_buffer);
  177. dmm_buffer_free(self->in_buffer);
  178. for (i = 0; i < ARRAY_SIZE(self->events); i++) {
  179. free(self->events[i]);
  180. self->events[i] = NULL;
  181. }
  182. if (self->dsp_error)
  183. goto leave;
  184. if (!dsp_node_terminate(self->dsp_handle, self->node, &exit_status))
  185. pr_err(self, "dsp node terminate failed: 0x%lx", exit_status);
  186. leave:
  187. if (!destroy_node(self))
  188. pr_err(self, "dsp node destroy failed");
  189. self->node = NULL;
  190. pr_info(self, "dsp node terminated");
  191. return TRUE;
  192. }
  193. static GstStateChangeReturn
  194. change_state(GstElement *element,
  195. GstStateChange transition)
  196. {
  197. GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
  198. GstDspDummy *self;
  199. self = GST_DSP_DUMMY(element);
  200. switch (transition) {
  201. case GST_STATE_CHANGE_NULL_TO_READY:
  202. if (!dsp_init(self)) {
  203. pr_err(self, "dsp init failed");
  204. return GST_STATE_CHANGE_FAILURE;
  205. }
  206. break;
  207. case GST_STATE_CHANGE_READY_TO_PAUSED:
  208. if (!_dsp_start(self)) {
  209. pr_err(self, "dsp start failed");
  210. return GST_STATE_CHANGE_FAILURE;
  211. }
  212. break;
  213. default:
  214. break;
  215. }
  216. ret = parent_class->change_state(element, transition);
  217. if (ret == GST_STATE_CHANGE_FAILURE)
  218. return ret;
  219. switch (transition) {
  220. case GST_STATE_CHANGE_PAUSED_TO_READY:
  221. if (!_dsp_stop(self)) {
  222. pr_err(self, "dsp stop failed");
  223. return GST_STATE_CHANGE_FAILURE;
  224. }
  225. break;
  226. case GST_STATE_CHANGE_READY_TO_NULL:
  227. if (!dsp_deinit(self)) {
  228. pr_err(self, "dsp deinit failed");
  229. return GST_STATE_CHANGE_FAILURE;
  230. }
  231. break;
  232. default:
  233. break;
  234. }
  235. return ret;
  236. }
  237. static void
  238. post_error(GstDspDummy *self,
  239. const char *message)
  240. {
  241. GError *gerror;
  242. GstMessage *gst_msg;
  243. gerror = g_error_new_literal(GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED, message);
  244. gst_msg = gst_message_new_error(GST_OBJECT(self), gerror, NULL);
  245. gst_element_post_message(GST_ELEMENT(self), gst_msg);
  246. g_error_free(gerror);
  247. }
  248. static void
  249. got_error(GstDspDummy *self,
  250. unsigned id,
  251. const char *message)
  252. {
  253. pr_err(self, "%s", message);
  254. post_error(self, message);
  255. self->dsp_error = id;
  256. }
  257. static bool check_events(GstDspDummy *self,
  258. struct dsp_node *node, struct dsp_msg *msg)
  259. {
  260. unsigned int index = 0;
  261. pr_debug(self, "waiting for events");
  262. if (!dsp_wait_for_events(self->dsp_handle, self->events, 3, &index, 1000)) {
  263. if (errno == ETIME) {
  264. pr_info(self, "timed out waiting for events");
  265. return true;
  266. }
  267. pr_err(self, "failed waiting for events: %i", errno);
  268. got_error(self, -1, "unable to get event");
  269. return false;
  270. }
  271. switch (index) {
  272. case 0:
  273. dsp_node_get_message(self->dsp_handle, node, msg, 100);
  274. pr_debug(self, "got dsp message: 0x%0x 0x%0x 0x%0x",
  275. msg->cmd, msg->arg_1, msg->arg_2);
  276. return true;
  277. case 1:
  278. pr_err(self, "got DSP MMUFAULT");
  279. return false;
  280. case 2:
  281. pr_err(self, "got DSP SYSERROR");
  282. return false;
  283. default:
  284. pr_err(self, "wrong event index");
  285. return false;
  286. }
  287. }
  288. static GstFlowReturn
  289. pad_chain(GstPad *pad,
  290. GstBuffer *buf)
  291. {
  292. GstDspDummy *self;
  293. GstFlowReturn ret;
  294. GstBuffer *out_buf;
  295. self = GST_DSP_DUMMY(GST_OBJECT_PARENT(pad));
  296. ret = gst_pad_alloc_buffer_and_set_caps(self->srcpad,
  297. GST_BUFFER_OFFSET_NONE,
  298. GST_BUFFER_SIZE(buf),
  299. GST_BUFFER_CAPS(buf),
  300. &out_buf);
  301. if (G_UNLIKELY(ret != GST_FLOW_OK)) {
  302. pr_err(self, "couldn't allocate buffer");
  303. ret = GST_FLOW_ERROR;
  304. goto leave;
  305. }
  306. /* map dsp to gpp address */
  307. gstdsp_map_buffer(self, buf, self->in_buffer);
  308. gstdsp_map_buffer(self, out_buf, self->out_buffer);
  309. if (self->in_buffer->need_copy) {
  310. memcpy(self->in_buffer->data, GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
  311. self->in_buffer->need_copy = false;
  312. }
  313. dmm_buffer_map(self->in_buffer);
  314. dmm_buffer_map(self->out_buffer);
  315. configure_dsp_node(self->dsp_handle, self->node, self->in_buffer, self->out_buffer);
  316. {
  317. struct dsp_msg msg;
  318. msg.cmd = 1;
  319. msg.arg_1 = self->in_buffer->len;
  320. dsp_node_put_message(self->dsp_handle, self->node, &msg, -1);
  321. dsp_node_get_message(self->dsp_handle, self->node, &msg, -1);
  322. if (!check_events(self, self->node, &msg)) {
  323. dmm_buffer_unmap(self->out_buffer);
  324. dmm_buffer_unmap(self->in_buffer);
  325. ret = GST_FLOW_ERROR;
  326. return ret;
  327. }
  328. }
  329. dmm_buffer_unmap(self->out_buffer);
  330. dmm_buffer_unmap(self->in_buffer);
  331. if (self->out_buffer->need_copy) {
  332. memcpy(GST_BUFFER_DATA(out_buf), self->out_buffer->data, GST_BUFFER_SIZE(out_buf));
  333. self->out_buffer->need_copy = false;
  334. }
  335. GST_BUFFER_TIMESTAMP(out_buf) = GST_BUFFER_TIMESTAMP(buf);
  336. ret = gst_pad_push(self->srcpad, out_buf);
  337. leave:
  338. gst_buffer_unref(buf);
  339. return ret;
  340. }
  341. static void
  342. instance_init(GTypeInstance *instance,
  343. gpointer g_class)
  344. {
  345. GstDspDummy *self;
  346. GstElementClass *element_class;
  347. element_class = GST_ELEMENT_CLASS(g_class);
  348. self = GST_DSP_DUMMY(instance);
  349. self->sinkpad =
  350. gst_pad_new_from_template(gst_element_class_get_pad_template(element_class, "sink"), "sink");
  351. gst_pad_set_chain_function(self->sinkpad, pad_chain);
  352. self->srcpad =
  353. gst_pad_new_from_template(gst_element_class_get_pad_template(element_class, "src"), "src");
  354. gst_pad_use_fixed_caps(self->srcpad);
  355. gst_element_add_pad(GST_ELEMENT(self), self->sinkpad);
  356. gst_element_add_pad(GST_ELEMENT(self), self->srcpad);
  357. }
  358. static void
  359. base_init(gpointer g_class)
  360. {
  361. GstElementClass *element_class;
  362. GstPadTemplate *template;
  363. element_class = GST_ELEMENT_CLASS(g_class);
  364. gst_element_class_set_details_simple(element_class,
  365. "DSP dummy element",
  366. "None",
  367. "Copies the input to the output",
  368. "Felipe Contreras");
  369. template = gst_pad_template_new("src", GST_PAD_SRC,
  370. GST_PAD_ALWAYS,
  371. generate_src_template());
  372. gst_element_class_add_pad_template(element_class, template);
  373. gst_object_unref(template);
  374. template = gst_pad_template_new("sink", GST_PAD_SINK,
  375. GST_PAD_ALWAYS,
  376. generate_sink_template());
  377. gst_element_class_add_pad_template(element_class, template);
  378. gst_object_unref(template);
  379. }
  380. static void
  381. class_init(gpointer g_class,
  382. gpointer class_data)
  383. {
  384. GstElementClass *gstelement_class;
  385. parent_class = g_type_class_peek_parent(g_class);
  386. gstelement_class = GST_ELEMENT_CLASS(g_class);
  387. gstelement_class->change_state = change_state;
  388. }
  389. GType
  390. gst_dsp_dummy_get_type(void)
  391. {
  392. static GType type;
  393. if (G_UNLIKELY(type == 0)) {
  394. GTypeInfo type_info = {
  395. .class_size = sizeof(GstDspDummyClass),
  396. .class_init = class_init,
  397. .base_init = base_init,
  398. .instance_size = sizeof(GstDspDummy),
  399. .instance_init = instance_init,
  400. };
  401. type = g_type_register_static(GST_TYPE_ELEMENT, "GstDspDummy", &type_info, 0);
  402. }
  403. return type;
  404. }