| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | /* Spa ALSA Sink
 | 
					
						
							|  |  |  |  * Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This library is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU Library General Public | 
					
						
							|  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							|  |  |  |  * version 2 of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * Library General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Library General Public | 
					
						
							|  |  |  |  * License along with this library; if not, write to the | 
					
						
							|  |  |  |  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, | 
					
						
							|  |  |  |  * Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stddef.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <asoundlib.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <spa/node.h>
 | 
					
						
							| 
									
										
										
										
											2016-07-05 17:58:34 +02:00
										 |  |  | #include <spa/audio/format.h>
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | typedef struct _SpaALSASink SpaALSASink; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char default_device[] = "default"; | 
					
						
							|  |  |  | static const uint32_t default_buffer_time = 10000; | 
					
						
							|  |  |  | static const uint32_t default_period_time = 5000; | 
					
						
							|  |  |  | static const bool default_period_event = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  |   SpaProps props; | 
					
						
							|  |  |  |   char device[64]; | 
					
						
							|  |  |  |   char device_name[128]; | 
					
						
							|  |  |  |   char card_name[128]; | 
					
						
							|  |  |  |   uint32_t buffer_time; | 
					
						
							|  |  |  |   uint32_t period_time; | 
					
						
							|  |  |  |   bool period_event; | 
					
						
							|  |  |  | } SpaALSASinkProps; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | reset_alsa_sink_props (SpaALSASinkProps *props) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   strncpy (props->device, default_device, 64); | 
					
						
							|  |  |  |   props->buffer_time = default_buffer_time; | 
					
						
							|  |  |  |   props->period_time = default_period_time; | 
					
						
							|  |  |  |   props->period_event = default_period_event; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							| 
									
										
										
										
											2016-07-06 19:43:37 +02:00
										 |  |  |   bool opened; | 
					
						
							| 
									
										
										
										
											2016-08-18 12:43:25 +02:00
										 |  |  |   bool have_buffers; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   snd_pcm_t *handle; | 
					
						
							|  |  |  |   snd_output_t *output; | 
					
						
							|  |  |  |   snd_pcm_sframes_t buffer_size; | 
					
						
							|  |  |  |   snd_pcm_sframes_t period_size; | 
					
						
							|  |  |  |   snd_pcm_channel_area_t areas[16]; | 
					
						
							|  |  |  |   bool running; | 
					
						
							| 
									
										
										
										
											2016-07-08 12:18:01 +02:00
										 |  |  |   SpaPollFd fds[16]; | 
					
						
							|  |  |  |   SpaPollItem poll; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | } SpaALSAState; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct _ALSABuffer ALSABuffer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct _ALSABuffer { | 
					
						
							|  |  |  |   SpaBuffer buffer; | 
					
						
							| 
									
										
										
										
											2016-08-24 16:26:58 +02:00
										 |  |  |   SpaMeta metas[2]; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   SpaMetaHeader header; | 
					
						
							| 
									
										
										
										
											2016-08-24 16:26:58 +02:00
										 |  |  |   SpaMetaRingbuffer ringbuffer; | 
					
						
							|  |  |  |   SpaData datas[1]; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct _SpaALSASink { | 
					
						
							|  |  |  |   SpaHandle handle; | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   SpaNode node; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-07 09:30:18 +02:00
										 |  |  |   SpaALSASinkProps props[2]; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   SpaEventCallback event_cb; | 
					
						
							|  |  |  |   void *user_data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool have_format; | 
					
						
							| 
									
										
										
										
											2016-08-26 19:22:50 +02:00
										 |  |  |   SpaFormatAudio query_format; | 
					
						
							|  |  |  |   SpaFormatAudio current_format; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   SpaALSAState state; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   SpaPortInfo info; | 
					
						
							| 
									
										
										
										
											2016-08-24 16:26:58 +02:00
										 |  |  |   SpaAllocParam *params[1]; | 
					
						
							|  |  |  |   SpaAllocParamBuffers param_buffers; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   SpaPortStatus status; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  |   SpaBuffer *buffers; | 
					
						
							|  |  |  |   unsigned int n_buffers; | 
					
						
							|  |  |  |   uint32_t input_buffer; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 16:26:58 +02:00
										 |  |  |   SpaMemory *mem; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   ALSABuffer buffer; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "alsa-utils.c"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const uint32_t min_uint32 = 1; | 
					
						
							|  |  |  | static const uint32_t max_uint32 = UINT32_MAX; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const SpaPropRangeInfo uint32_range[] = { | 
					
						
							|  |  |  |   { "min", "Minimum value", 4, &min_uint32 }, | 
					
						
							|  |  |  |   { "max", "Maximum value", 4, &max_uint32 }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum { | 
					
						
							|  |  |  |   PROP_ID_DEVICE, | 
					
						
							|  |  |  |   PROP_ID_DEVICE_NAME, | 
					
						
							|  |  |  |   PROP_ID_CARD_NAME, | 
					
						
							|  |  |  |   PROP_ID_BUFFER_TIME, | 
					
						
							|  |  |  |   PROP_ID_PERIOD_TIME, | 
					
						
							|  |  |  |   PROP_ID_PERIOD_EVENT, | 
					
						
							|  |  |  |   PROP_ID_LAST, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const SpaPropInfo prop_info[] = | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-08-26 17:43:48 +02:00
										 |  |  |   { PROP_ID_DEVICE,             offsetof (SpaALSASinkProps, device), | 
					
						
							|  |  |  |                                 "device", "ALSA device, as defined in an asound configuration file", | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                 SPA_PROP_FLAG_READWRITE, | 
					
						
							|  |  |  |                                 SPA_PROP_TYPE_STRING, 63, | 
					
						
							|  |  |  |                                 SPA_PROP_RANGE_TYPE_NONE, 0, NULL, | 
					
						
							| 
									
										
										
										
											2016-08-26 17:43:48 +02:00
										 |  |  |                                 NULL }, | 
					
						
							|  |  |  |   { PROP_ID_DEVICE_NAME,        offsetof (SpaALSASinkProps, device_name), | 
					
						
							|  |  |  |                                 "device-name", "Human-readable name of the sound device", | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                 SPA_PROP_FLAG_READABLE, | 
					
						
							|  |  |  |                                 SPA_PROP_TYPE_STRING, 127, | 
					
						
							|  |  |  |                                 SPA_PROP_RANGE_TYPE_NONE, 0, NULL, | 
					
						
							| 
									
										
										
										
											2016-08-26 17:43:48 +02:00
										 |  |  |                                 NULL }, | 
					
						
							|  |  |  |   { PROP_ID_CARD_NAME,          offsetof (SpaALSASinkProps, card_name), | 
					
						
							|  |  |  |                                 "card-name", "Human-readable name of the sound card", | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                 SPA_PROP_FLAG_READABLE, | 
					
						
							|  |  |  |                                 SPA_PROP_TYPE_STRING, 127, | 
					
						
							|  |  |  |                                 SPA_PROP_RANGE_TYPE_NONE, 0, NULL, | 
					
						
							| 
									
										
										
										
											2016-08-26 17:43:48 +02:00
										 |  |  |                                 NULL }, | 
					
						
							|  |  |  |   { PROP_ID_BUFFER_TIME,        offsetof (SpaALSASinkProps, buffer_time), | 
					
						
							|  |  |  |                                 "buffer-time", "The total size of the buffer in time", | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                 SPA_PROP_FLAG_READWRITE, | 
					
						
							|  |  |  |                                 SPA_PROP_TYPE_UINT32, sizeof (uint32_t), | 
					
						
							|  |  |  |                                 SPA_PROP_RANGE_TYPE_MIN_MAX, 2, uint32_range, | 
					
						
							| 
									
										
										
										
											2016-08-26 17:43:48 +02:00
										 |  |  |                                 NULL }, | 
					
						
							|  |  |  |   { PROP_ID_PERIOD_TIME,        offsetof (SpaALSASinkProps, period_time), | 
					
						
							|  |  |  |                                 "period-time", "The size of a period in time", | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                 SPA_PROP_FLAG_READWRITE, | 
					
						
							|  |  |  |                                 SPA_PROP_TYPE_UINT32, sizeof (uint32_t), | 
					
						
							|  |  |  |                                 SPA_PROP_RANGE_TYPE_MIN_MAX, 2, uint32_range, | 
					
						
							| 
									
										
										
										
											2016-08-26 17:43:48 +02:00
										 |  |  |                                 NULL }, | 
					
						
							|  |  |  |   { PROP_ID_PERIOD_EVENT,       offsetof (SpaALSASinkProps, period_event), | 
					
						
							|  |  |  |                                 "period-event", "Generate an event each period", | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                 SPA_PROP_FLAG_READWRITE, | 
					
						
							|  |  |  |                                 SPA_PROP_TYPE_BOOL, sizeof (bool), | 
					
						
							|  |  |  |                                 SPA_PROP_RANGE_TYPE_NONE, 0, NULL, | 
					
						
							| 
									
										
										
										
											2016-08-26 17:43:48 +02:00
										 |  |  |                                 NULL }, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_get_props (SpaNode       *node, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                               SpaProps     **props) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   SpaALSASink *this; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   if (node == NULL || node->handle == NULL || props == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   this = (SpaALSASink *) node->handle; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-07 09:30:18 +02:00
										 |  |  |   memcpy (&this->props[0], &this->props[1], sizeof (this->props[1])); | 
					
						
							|  |  |  |   *props = &this->props[0].props; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_set_props (SpaNode         *node, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                               const SpaProps  *props) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   SpaALSASink *this; | 
					
						
							|  |  |  |   SpaALSASinkProps *p; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   SpaResult res; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   if (node == NULL || node->handle == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   this = (SpaALSASink *) node->handle; | 
					
						
							|  |  |  |   p = &this->props[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   if (props == NULL) { | 
					
						
							|  |  |  |     reset_alsa_sink_props (p); | 
					
						
							|  |  |  |     return SPA_RESULT_OK; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   res = spa_props_copy (props, &p->props); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_send_command (SpaNode       *node, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                  SpaCommand    *command) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   SpaALSASink *this; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   if (node == NULL || node->handle == NULL || command == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   this = (SpaALSASink *) node->handle; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   switch (command->type) { | 
					
						
							|  |  |  |     case SPA_COMMAND_INVALID: | 
					
						
							|  |  |  |       return SPA_RESULT_INVALID_COMMAND; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-06 19:43:37 +02:00
										 |  |  |     case SPA_COMMAND_START: | 
					
						
							|  |  |  |       spa_alsa_start (this); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |       if (this->event_cb) { | 
					
						
							|  |  |  |         SpaEvent event; | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  |         SpaEventStateChange sc; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  |         event.type = SPA_EVENT_TYPE_STATE_CHANGE; | 
					
						
							|  |  |  |         event.data = ≻ | 
					
						
							|  |  |  |         event.size = sizeof (sc); | 
					
						
							|  |  |  |         sc.state = SPA_NODE_STATE_STREAMING; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |         this->event_cb (node, &event, this->user_data); | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							| 
									
										
										
										
											2016-08-25 14:10:38 +02:00
										 |  |  |     case SPA_COMMAND_PAUSE: | 
					
						
							| 
									
										
										
										
											2016-07-06 19:43:37 +02:00
										 |  |  |       spa_alsa_stop (this); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |       if (this->event_cb) { | 
					
						
							|  |  |  |         SpaEvent event; | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  |         SpaEventStateChange sc; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  |         event.type = SPA_EVENT_TYPE_STATE_CHANGE; | 
					
						
							|  |  |  |         event.data = ≻ | 
					
						
							|  |  |  |         event.size = sizeof (sc); | 
					
						
							| 
									
										
										
										
											2016-08-25 14:10:38 +02:00
										 |  |  |         sc.state = SPA_NODE_STATE_PAUSED; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |         this->event_cb (node, &event, this->user_data); | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case SPA_COMMAND_FLUSH: | 
					
						
							|  |  |  |     case SPA_COMMAND_DRAIN: | 
					
						
							|  |  |  |     case SPA_COMMAND_MARKER: | 
					
						
							|  |  |  |       return SPA_RESULT_NOT_IMPLEMENTED; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_set_event_callback (SpaNode          *node, | 
					
						
							|  |  |  |                                        SpaEventCallback  event, | 
					
						
							|  |  |  |                                        void             *user_data) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   SpaALSASink *this; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   if (node == NULL || node->handle == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   this = (SpaALSASink *) node->handle; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   this->event_cb = event; | 
					
						
							|  |  |  |   this->user_data = user_data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_get_n_ports (SpaNode       *node, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                 unsigned int  *n_input_ports, | 
					
						
							|  |  |  |                                 unsigned int  *max_input_ports, | 
					
						
							|  |  |  |                                 unsigned int  *n_output_ports, | 
					
						
							|  |  |  |                                 unsigned int  *max_output_ports) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   if (node == NULL || node->handle == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (n_input_ports) | 
					
						
							|  |  |  |     *n_input_ports = 1; | 
					
						
							|  |  |  |   if (n_output_ports) | 
					
						
							|  |  |  |     *n_output_ports = 0; | 
					
						
							|  |  |  |   if (max_input_ports) | 
					
						
							|  |  |  |     *max_input_ports = 1; | 
					
						
							|  |  |  |   if (max_output_ports) | 
					
						
							|  |  |  |     *max_output_ports = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_get_port_ids (SpaNode       *node, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                  unsigned int   n_input_ports, | 
					
						
							|  |  |  |                                  uint32_t      *input_ids, | 
					
						
							|  |  |  |                                  unsigned int   n_output_ports, | 
					
						
							|  |  |  |                                  uint32_t      *output_ids) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   if (node == NULL || node->handle == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-05 16:23:40 +02:00
										 |  |  |   if (n_input_ports > 0 && input_ids != NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     input_ids[0] = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_add_port (SpaNode        *node, | 
					
						
							|  |  |  |                              uint32_t        port_id) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   return SPA_RESULT_NOT_IMPLEMENTED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_remove_port (SpaNode        *node, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                 uint32_t        port_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return SPA_RESULT_NOT_IMPLEMENTED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_port_enum_formats (SpaNode         *node, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                       uint32_t         port_id, | 
					
						
							| 
									
										
										
										
											2016-07-15 18:22:29 +02:00
										 |  |  |                                       SpaFormat      **format, | 
					
						
							|  |  |  |                                       const SpaFormat *filter, | 
					
						
							|  |  |  |                                       void           **state) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   SpaALSASink *this; | 
					
						
							| 
									
										
										
										
											2016-07-15 18:22:29 +02:00
										 |  |  |   int index; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   if (node == NULL || node->handle == NULL || format == NULL || state == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   this = (SpaALSASink *) node->handle; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   if (port_id != 0) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-15 18:22:29 +02:00
										 |  |  |   index = (*state == NULL ? 0 : *(int*)state); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   switch (index) { | 
					
						
							|  |  |  |     case 0: | 
					
						
							| 
									
										
										
										
											2016-08-26 19:22:50 +02:00
										 |  |  |       spa_format_audio_init (SPA_MEDIA_TYPE_AUDIO, | 
					
						
							|  |  |  |                              SPA_MEDIA_SUBTYPE_RAW, | 
					
						
							|  |  |  |                              &this->query_format); | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |       break; | 
					
						
							|  |  |  |     case 1: | 
					
						
							| 
									
										
										
										
											2016-08-26 19:22:50 +02:00
										 |  |  |       spa_format_audio_init (SPA_MEDIA_TYPE_AUDIO, | 
					
						
							|  |  |  |                              SPA_MEDIA_SUBTYPE_AAC, | 
					
						
							|  |  |  |                              &this->query_format); | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return SPA_RESULT_ENUM_END; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   *format = &this->query_format.format; | 
					
						
							| 
									
										
										
										
											2016-07-15 18:22:29 +02:00
										 |  |  |   *(int*)state = ++index; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_port_set_format (SpaNode            *node, | 
					
						
							| 
									
										
										
										
											2016-07-18 10:35:02 +02:00
										 |  |  |                                     uint32_t            port_id, | 
					
						
							|  |  |  |                                     SpaPortFormatFlags  flags, | 
					
						
							|  |  |  |                                     const SpaFormat    *format) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   SpaALSASink *this; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   SpaResult res; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   if (node == NULL || node->handle == NULL || format == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   this = (SpaALSASink *) node->handle; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   if (port_id != 0) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (format == NULL) { | 
					
						
							|  |  |  |     this->have_format = false; | 
					
						
							|  |  |  |     return SPA_RESULT_OK; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-26 19:22:50 +02:00
										 |  |  |   if ((res = spa_format_audio_parse (format, &this->current_format)) < 0) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return res; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-18 12:43:25 +02:00
										 |  |  |   if (alsa_set_format (this, &this->current_format, false) < 0) | 
					
						
							|  |  |  |     return SPA_RESULT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 16:26:58 +02:00
										 |  |  |   this->info.flags = SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS; | 
					
						
							|  |  |  |   this->info.maxbuffering = -1; | 
					
						
							|  |  |  |   this->info.latency = -1; | 
					
						
							|  |  |  |   this->info.n_params = 1; | 
					
						
							|  |  |  |   this->params[0] = &this->param_buffers.param; | 
					
						
							|  |  |  |   this->param_buffers.param.type = SPA_ALLOC_PARAM_TYPE_BUFFERS; | 
					
						
							|  |  |  |   this->param_buffers.param.size = sizeof (this->param_buffers); | 
					
						
							|  |  |  |   this->param_buffers.minsize = 1; | 
					
						
							|  |  |  |   this->param_buffers.stride = 0; | 
					
						
							|  |  |  |   this->param_buffers.min_buffers = 1; | 
					
						
							|  |  |  |   this->param_buffers.max_buffers = 8; | 
					
						
							|  |  |  |   this->param_buffers.align = 16; | 
					
						
							|  |  |  |   this->info.features = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   this->have_format = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_port_get_format (SpaNode          *node, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                     uint32_t          port_id, | 
					
						
							|  |  |  |                                     const SpaFormat **format) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   SpaALSASink *this; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   if (node == NULL || node->handle == NULL || format == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   this = (SpaALSASink *) node->handle; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   if (port_id != 0) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!this->have_format) | 
					
						
							|  |  |  |     return SPA_RESULT_NO_FORMAT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   *format = &this->current_format.format; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_port_get_info (SpaNode            *node, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                   uint32_t            port_id, | 
					
						
							|  |  |  |                                   const SpaPortInfo **info) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   SpaALSASink *this; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   if (node == NULL || node->handle == NULL || info == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   this = (SpaALSASink *) node->handle; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   if (port_id != 0) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   *info = &this->info; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_port_get_props (SpaNode    *node, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                    uint32_t    port_id, | 
					
						
							|  |  |  |                                    SpaProps  **props) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return SPA_RESULT_NOT_IMPLEMENTED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_port_set_props (SpaNode         *node, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                    uint32_t         port_id, | 
					
						
							|  |  |  |                                    const SpaProps  *props) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return SPA_RESULT_NOT_IMPLEMENTED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_port_use_buffers (SpaNode         *node, | 
					
						
							| 
									
										
										
										
											2016-07-08 20:12:56 +02:00
										 |  |  |                                      uint32_t         port_id, | 
					
						
							| 
									
										
										
										
											2016-07-11 17:45:54 +02:00
										 |  |  |                                      SpaBuffer      **buffers, | 
					
						
							| 
									
										
										
										
											2016-07-08 20:12:56 +02:00
										 |  |  |                                      uint32_t         n_buffers) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return SPA_RESULT_NOT_IMPLEMENTED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_port_alloc_buffers (SpaNode         *node, | 
					
						
							| 
									
										
										
										
											2016-07-08 20:12:56 +02:00
										 |  |  |                                        uint32_t         port_id, | 
					
						
							| 
									
										
										
										
											2016-07-13 18:29:55 +02:00
										 |  |  |                                        SpaAllocParam  **params, | 
					
						
							|  |  |  |                                        uint32_t         n_params, | 
					
						
							| 
									
										
										
										
											2016-07-08 20:12:56 +02:00
										 |  |  |                                        SpaBuffer      **buffers, | 
					
						
							|  |  |  |                                        uint32_t        *n_buffers) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-08-24 16:26:58 +02:00
										 |  |  |   SpaALSASink *this; | 
					
						
							|  |  |  |   ALSABuffer *b; | 
					
						
							|  |  |  |   SpaALSAState *state; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (node == NULL || node->handle == NULL || buffers == NULL) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (port_id != 0) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   this = (SpaALSASink *) node->handle; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!this->have_format) | 
					
						
							|  |  |  |     return SPA_RESULT_NO_FORMAT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   state = &this->state; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!this->mem) | 
					
						
							|  |  |  |     this->mem = spa_memory_alloc_with_fd (SPA_MEMORY_POOL_SHARED, NULL, state->buffer_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   b = &this->buffer; | 
					
						
							|  |  |  |   b->buffer.id = 0; | 
					
						
							|  |  |  |   b->buffer.mem.mem.pool_id = -1; | 
					
						
							|  |  |  |   b->buffer.mem.mem.id = -1; | 
					
						
							|  |  |  |   b->buffer.mem.offset = 0; | 
					
						
							|  |  |  |   b->buffer.mem.size = sizeof (ALSABuffer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   b->buffer.n_metas = 2; | 
					
						
							|  |  |  |   b->buffer.metas = offsetof (ALSABuffer, metas); | 
					
						
							|  |  |  |   b->buffer.n_datas = 1; | 
					
						
							|  |  |  |   b->buffer.datas = offsetof (ALSABuffer, datas); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   b->header.flags = 0; | 
					
						
							|  |  |  |   b->header.seq = 0; | 
					
						
							|  |  |  |   b->header.pts = 0; | 
					
						
							|  |  |  |   b->header.dts_offset = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   b->metas[0].type = SPA_META_TYPE_HEADER; | 
					
						
							|  |  |  |   b->metas[0].offset = offsetof (ALSABuffer, header); | 
					
						
							|  |  |  |   b->metas[0].size = sizeof (b->header); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   b->ringbuffer.readindex = 0; | 
					
						
							|  |  |  |   b->ringbuffer.writeindex = 0; | 
					
						
							|  |  |  |   b->ringbuffer.size = 0; | 
					
						
							|  |  |  |   b->ringbuffer.size_mask = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   b->metas[1].type = SPA_META_TYPE_RINGBUFFER; | 
					
						
							|  |  |  |   b->metas[1].offset = offsetof (ALSABuffer, ringbuffer); | 
					
						
							|  |  |  |   b->metas[1].size = sizeof (b->ringbuffer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   b->datas[0].mem.mem = this->mem->mem; | 
					
						
							|  |  |  |   b->datas[0].mem.offset = 0; | 
					
						
							|  |  |  |   b->datas[0].mem.size = state->buffer_size; | 
					
						
							|  |  |  |   b->datas[0].stride = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   buffers[0] = &b->buffer; | 
					
						
							|  |  |  |   *n_buffers = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							| 
									
										
										
										
											2016-07-08 20:12:56 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  | static SpaResult | 
					
						
							|  |  |  | spa_alsa_sink_node_port_reuse_buffer (SpaNode         *node, | 
					
						
							|  |  |  |                                       uint32_t         port_id, | 
					
						
							| 
									
										
										
										
											2016-08-24 16:26:58 +02:00
										 |  |  |                                       uint32_t         buffer_id) | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  |   return SPA_RESULT_NOT_IMPLEMENTED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							|  |  |  | spa_alsa_sink_node_port_get_status (SpaNode              *node, | 
					
						
							|  |  |  |                                     uint32_t              port_id, | 
					
						
							|  |  |  |                                     const SpaPortStatus **status) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   SpaALSASink *this; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (node == NULL || node->handle == NULL || status == NULL) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   this = (SpaALSASink *) node->handle; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (port_id != 0) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   *status = &this->status; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-08 20:12:56 +02:00
										 |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_port_push_input (SpaNode        *node, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                     unsigned int    n_info, | 
					
						
							|  |  |  |                                     SpaInputInfo   *info) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   SpaALSASink *this; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   unsigned int i; | 
					
						
							|  |  |  |   bool have_error = false, have_enough = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   if (node == NULL || node->handle == NULL || n_info == 0 || info == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   this = (SpaALSASink *) node->handle; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   for (i = 0; i < n_info; i++) { | 
					
						
							|  |  |  |     if (info[i].port_id != 0) { | 
					
						
							|  |  |  |       info[i].status = SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  |       have_error = true; | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  |     if (info[i].buffer_id != SPA_ID_INVALID) { | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |       if (!this->have_format) { | 
					
						
							|  |  |  |         info[i].status = SPA_RESULT_NO_FORMAT; | 
					
						
							|  |  |  |         have_error = true; | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  |       if (this->input_buffer != -1) { | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |         info[i].status = SPA_RESULT_HAVE_ENOUGH_INPUT; | 
					
						
							|  |  |  |         have_enough = true; | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  |       this->input_buffer = info[i].buffer_id; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     info[i].status = SPA_RESULT_OK; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (have_error) | 
					
						
							|  |  |  |     return SPA_RESULT_ERROR; | 
					
						
							|  |  |  |   if (have_enough) | 
					
						
							|  |  |  |     return SPA_RESULT_HAVE_ENOUGH_INPUT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_port_pull_output (SpaNode        *node, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                      unsigned int    n_info, | 
					
						
							|  |  |  |                                      SpaOutputInfo  *info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const SpaNode alsasink_node = { | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   NULL, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   sizeof (SpaNode), | 
					
						
							| 
									
										
										
										
											2016-09-05 16:23:40 +02:00
										 |  |  |   SPA_NODE_STATE_INIT, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   spa_alsa_sink_node_get_props, | 
					
						
							|  |  |  |   spa_alsa_sink_node_set_props, | 
					
						
							|  |  |  |   spa_alsa_sink_node_send_command, | 
					
						
							|  |  |  |   spa_alsa_sink_node_set_event_callback, | 
					
						
							|  |  |  |   spa_alsa_sink_node_get_n_ports, | 
					
						
							|  |  |  |   spa_alsa_sink_node_get_port_ids, | 
					
						
							|  |  |  |   spa_alsa_sink_node_add_port, | 
					
						
							|  |  |  |   spa_alsa_sink_node_remove_port, | 
					
						
							| 
									
										
										
										
											2016-07-08 20:12:56 +02:00
										 |  |  |   spa_alsa_sink_node_port_enum_formats, | 
					
						
							|  |  |  |   spa_alsa_sink_node_port_set_format, | 
					
						
							|  |  |  |   spa_alsa_sink_node_port_get_format, | 
					
						
							|  |  |  |   spa_alsa_sink_node_port_get_info, | 
					
						
							|  |  |  |   spa_alsa_sink_node_port_get_props, | 
					
						
							|  |  |  |   spa_alsa_sink_node_port_set_props, | 
					
						
							|  |  |  |   spa_alsa_sink_node_port_use_buffers, | 
					
						
							|  |  |  |   spa_alsa_sink_node_port_alloc_buffers, | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  |   spa_alsa_sink_node_port_reuse_buffer, | 
					
						
							| 
									
										
										
										
											2016-07-08 20:12:56 +02:00
										 |  |  |   spa_alsa_sink_node_port_get_status, | 
					
						
							|  |  |  |   spa_alsa_sink_node_port_push_input, | 
					
						
							|  |  |  |   spa_alsa_sink_node_port_pull_output, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							|  |  |  | spa_alsa_sink_get_interface (SpaHandle               *handle, | 
					
						
							|  |  |  |                              uint32_t                 interface_id, | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |                              void                   **interface) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   SpaALSASink *this; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   if (handle == NULL || interface == NULL) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   this = (SpaALSASink *) handle; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   switch (interface_id) { | 
					
						
							|  |  |  |     case SPA_INTERFACE_ID_NODE: | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |       *interface = &this->node; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return SPA_RESULT_UNKNOWN_INTERFACE; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-01 10:04:25 +02:00
										 |  |  | static SpaResult | 
					
						
							|  |  |  | alsa_sink_clear (SpaHandle *handle) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 18:29:55 +02:00
										 |  |  | static SpaResult | 
					
						
							|  |  |  | alsa_sink_init (const SpaHandleFactory  *factory, | 
					
						
							|  |  |  |                 SpaHandle               *handle) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   SpaALSASink *this; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 18:29:55 +02:00
										 |  |  |   if (factory == NULL || handle == NULL) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   handle->get_interface = spa_alsa_sink_get_interface; | 
					
						
							| 
									
										
										
										
											2016-09-01 10:04:25 +02:00
										 |  |  |   handle->clear = alsa_sink_clear; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   this = (SpaALSASink *) handle; | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   this->node = alsasink_node; | 
					
						
							|  |  |  |   this->node.handle = handle; | 
					
						
							| 
									
										
										
										
											2016-07-07 09:30:18 +02:00
										 |  |  |   this->props[1].props.n_prop_info = PROP_ID_LAST; | 
					
						
							|  |  |  |   this->props[1].props.prop_info = prop_info; | 
					
						
							|  |  |  |   reset_alsa_sink_props (&this->props[1]); | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   this->status.flags = SPA_PORT_STATUS_FLAG_NEED_INPUT; | 
					
						
							| 
									
										
										
										
											2016-07-13 18:29:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-07-13 18:29:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static const SpaInterfaceInfo alsa_sink_interfaces[] = | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   { SPA_INTERFACE_ID_NODE, | 
					
						
							|  |  |  |     SPA_INTERFACE_ID_NODE_NAME, | 
					
						
							|  |  |  |     SPA_INTERFACE_ID_NODE_DESCRIPTION, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							|  |  |  | alsa_sink_enum_interface_info (const SpaHandleFactory  *factory, | 
					
						
							| 
									
										
										
										
											2016-07-15 18:22:29 +02:00
										 |  |  |                                const SpaInterfaceInfo **info, | 
					
						
							|  |  |  |                                void                   **state) | 
					
						
							| 
									
										
										
										
											2016-07-13 18:29:55 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-15 18:22:29 +02:00
										 |  |  |   int index; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (factory == NULL || info == NULL || state == NULL) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   index = (*state == NULL ? 0 : *(int*)state); | 
					
						
							| 
									
										
										
										
											2016-07-13 18:29:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-15 18:22:29 +02:00
										 |  |  |   switch (index) { | 
					
						
							|  |  |  |     case 0: | 
					
						
							|  |  |  |       *info = &alsa_sink_interfaces[index]; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return SPA_RESULT_ENUM_END; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   *(int*)state = ++index; | 
					
						
							| 
									
										
										
										
											2016-07-13 18:29:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const SpaHandleFactory spa_alsa_sink_factory = | 
					
						
							|  |  |  | { "alsa-sink", | 
					
						
							|  |  |  |   NULL, | 
					
						
							|  |  |  |   sizeof (SpaALSASink), | 
					
						
							|  |  |  |   alsa_sink_init, | 
					
						
							|  |  |  |   alsa_sink_enum_interface_info, | 
					
						
							|  |  |  | }; |