| 
									
										
										
										
											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-11-03 19:41:53 +01:00
										 |  |  | #include <lib/props.h>
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-19 09:16:58 +02:00
										 |  |  | #include "alsa-utils.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  | #define CHECK_PORT(this,d,p)    ((d) == SPA_DIRECTION_INPUT && (p) == 0)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-19 09:16:58 +02:00
										 |  |  | typedef struct _SpaALSAState SpaALSASink; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static const char default_device[] = "default"; | 
					
						
							| 
									
										
										
										
											2017-04-03 16:54:44 +02:00
										 |  |  | static const uint32_t default_min_latency = 1024; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2016-09-19 09:16:58 +02:00
										 |  |  | reset_alsa_sink_props (SpaALSAProps *props) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   strncpy (props->device, default_device, 64); | 
					
						
							| 
									
										
										
										
											2017-04-03 16:54:44 +02:00
										 |  |  |   props->min_latency = default_min_latency; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-12 15:25:53 +02:00
										 |  |  | static void | 
					
						
							|  |  |  | update_state (SpaALSASink *this, SpaNodeState state) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-11-03 19:41:53 +01:00
										 |  |  |   spa_log_info (this->log, "update state %d", state); | 
					
						
							| 
									
										
										
										
											2016-09-12 15:25:53 +02:00
										 |  |  |   this->node.state = state; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-17 11:58:09 +01:00
										 |  |  | #define PROP(f,key,type,...)                                                    \
 | 
					
						
							| 
									
										
										
										
											2017-03-31 11:48:24 +02:00
										 |  |  |           SPA_POD_PROP (f,key,0,type,1,__VA_ARGS__) | 
					
						
							| 
									
										
										
										
											2017-03-17 11:58:09 +01:00
										 |  |  | #define PROP_MM(f,key,type,...)                                                 \
 | 
					
						
							| 
									
										
										
										
											2017-03-31 11:48:24 +02:00
										 |  |  |           SPA_POD_PROP (f,key,SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__) | 
					
						
							| 
									
										
										
										
											2017-03-17 11:58:09 +01:00
										 |  |  | #define PROP_U_MM(f,key,type,...)                                               \
 | 
					
						
							| 
									
										
										
										
											2017-03-31 11:48:24 +02:00
										 |  |  |           SPA_POD_PROP (f,key,SPA_POD_PROP_FLAG_UNSET |                         \ | 
					
						
							| 
									
										
										
										
											2017-03-17 11:58:09 +01:00
										 |  |  |                               SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__) | 
					
						
							|  |  |  | #define PROP_U_EN(f,key,type,n,...)                                             \
 | 
					
						
							| 
									
										
										
										
											2017-03-31 11:48:24 +02:00
										 |  |  |           SPA_POD_PROP (f,key,SPA_POD_PROP_FLAG_UNSET |                         \ | 
					
						
							| 
									
										
										
										
											2017-03-17 11:58:09 +01:00
										 |  |  |                               SPA_POD_PROP_RANGE_ENUM,type,n,__VA_ARGS__) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2017-02-28 10:48:53 +01:00
										 |  |  |   SpaPODBuilder b = { NULL,  }; | 
					
						
							| 
									
										
										
										
											2017-03-17 11:58:09 +01:00
										 |  |  |   SpaPODFrame f[2]; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   if (node == NULL || props == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   this = SPA_CONTAINER_OF (node, SpaALSASink, node); | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 14:07:02 +01:00
										 |  |  |   spa_pod_builder_init (&b, this->props_buffer, sizeof (this->props_buffer)); | 
					
						
							| 
									
										
										
										
											2017-02-28 10:48:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |   spa_pod_builder_props (&b, &f[0], this->type.props, | 
					
						
							|  |  |  |         PROP    (&f[1], this->type.prop_device,      -SPA_POD_TYPE_STRING, this->props.device, sizeof (this->props.device)), | 
					
						
							|  |  |  |         PROP    (&f[1], this->type.prop_device_name, -SPA_POD_TYPE_STRING, this->props.device_name, sizeof (this->props.device_name)), | 
					
						
							|  |  |  |         PROP    (&f[1], this->type.prop_card_name,   -SPA_POD_TYPE_STRING, this->props.card_name, sizeof (this->props.card_name)), | 
					
						
							| 
									
										
										
										
											2017-04-03 16:54:44 +02:00
										 |  |  |         PROP_MM (&f[1], this->type.prop_min_latency,  SPA_POD_TYPE_INT,    this->props.min_latency, 1, INT32_MAX)); | 
					
						
							| 
									
										
										
										
											2017-02-28 10:48:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-17 11:58:09 +01:00
										 |  |  |   *props = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaProps); | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   if (node == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   this = SPA_CONTAINER_OF (node, SpaALSASink, node); | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   if (props == NULL) { | 
					
						
							| 
									
										
										
										
											2017-02-28 10:48:53 +01:00
										 |  |  |     reset_alsa_sink_props (&this->props); | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_OK; | 
					
						
							| 
									
										
										
										
											2017-02-28 10:48:53 +01:00
										 |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2017-03-17 11:58:09 +01:00
										 |  |  |     spa_props_query (props, | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |         this->type.prop_device,      -SPA_POD_TYPE_STRING, this->props.device, sizeof (this->props.device), | 
					
						
							| 
									
										
										
										
											2017-04-03 16:54:44 +02:00
										 |  |  |         this->type.prop_min_latency,  SPA_POD_TYPE_INT,    &this->props.min_latency, | 
					
						
							| 
									
										
										
										
											2017-03-17 11:58:09 +01:00
										 |  |  |         0); | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-28 10:48:53 +01:00
										 |  |  |   return SPA_RESULT_OK; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-11-18 17:46:01 +01:00
										 |  |  | do_send_event (SpaLoop        *loop, | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |                bool            async, | 
					
						
							|  |  |  |                uint32_t        seq, | 
					
						
							|  |  |  |                size_t          size, | 
					
						
							|  |  |  |                void           *data, | 
					
						
							|  |  |  |                void           *user_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   SpaALSASink *this = user_data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   this->event_cb (&this->node, data, this->user_data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-11-18 17:46:01 +01:00
										 |  |  | do_command (SpaLoop        *loop, | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |             bool            async, | 
					
						
							|  |  |  |             uint32_t        seq, | 
					
						
							|  |  |  |             size_t          size, | 
					
						
							|  |  |  |             void           *data, | 
					
						
							|  |  |  |             void           *user_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   SpaALSASink *this = user_data; | 
					
						
							|  |  |  |   SpaResult res; | 
					
						
							| 
									
										
										
										
											2017-03-22 10:04:24 +01:00
										 |  |  |   SpaCommand *cmd = data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |   if (SPA_COMMAND_TYPE (cmd) == this->type.command_node.Start || | 
					
						
							|  |  |  |       SPA_COMMAND_TYPE (cmd) == this->type.command_node.Pause) { | 
					
						
							| 
									
										
										
										
											2017-03-22 10:04:24 +01:00
										 |  |  |     res = spa_node_port_send_command (&this->node, | 
					
						
							|  |  |  |                                       SPA_DIRECTION_INPUT, | 
					
						
							|  |  |  |                                       0, | 
					
						
							|  |  |  |                                       cmd); | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-03-22 10:04:24 +01:00
										 |  |  |   else | 
					
						
							|  |  |  |     res = SPA_RESULT_NOT_IMPLEMENTED; | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (async) { | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |     SpaEventNodeAsyncComplete ac = SPA_EVENT_NODE_ASYNC_COMPLETE_INIT (this->type.event_node.AsyncComplete, | 
					
						
							| 
									
										
										
										
											2017-03-21 20:39:20 +01:00
										 |  |  |                                                                        seq, res); | 
					
						
							| 
									
										
										
										
											2016-11-18 17:46:01 +01:00
										 |  |  |     spa_loop_invoke (this->main_loop, | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |                      do_send_event, | 
					
						
							|  |  |  |                      SPA_ID_INVALID, | 
					
						
							|  |  |  |                      sizeof (ac), | 
					
						
							|  |  |  |                      &ac, | 
					
						
							|  |  |  |                      this); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2017-03-22 10:04:24 +01:00
										 |  |  | spa_alsa_sink_node_send_command (SpaNode    *node, | 
					
						
							|  |  |  |                                  SpaCommand *command) | 
					
						
							| 
									
										
										
										
											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-10-12 17:27:29 +02:00
										 |  |  |   if (node == NULL || command == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   this = SPA_CONTAINER_OF (node, SpaALSASink, node); | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |   if (SPA_COMMAND_TYPE (command) == this->type.command_node.Start || | 
					
						
							|  |  |  |       SPA_COMMAND_TYPE (command) == this->type.command_node.Pause) { | 
					
						
							| 
									
										
										
										
											2017-03-22 10:04:24 +01:00
										 |  |  |     if (!this->have_format) | 
					
						
							|  |  |  |       return SPA_RESULT_NO_FORMAT; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-22 10:04:24 +01:00
										 |  |  |     if (this->n_buffers == 0) | 
					
						
							|  |  |  |       return SPA_RESULT_NO_BUFFERS; | 
					
						
							| 
									
										
										
										
											2016-07-06 19:43:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-22 10:04:24 +01:00
										 |  |  |     return spa_loop_invoke (this->data_loop, | 
					
						
							|  |  |  |                             do_command, | 
					
						
							|  |  |  |                             ++this->seq, | 
					
						
							|  |  |  |                             SPA_POD_SIZE (command), | 
					
						
							|  |  |  |                             command, | 
					
						
							|  |  |  |                             this); | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-03-22 10:04:24 +01:00
										 |  |  |   else | 
					
						
							|  |  |  |     return SPA_RESULT_NOT_IMPLEMENTED; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-09-06 16:43:37 +02:00
										 |  |  | spa_alsa_sink_node_set_event_callback (SpaNode              *node, | 
					
						
							| 
									
										
										
										
											2017-03-23 21:15:52 +01:00
										 |  |  |                                        SpaEventNodeCallback  event, | 
					
						
							| 
									
										
										
										
											2016-09-06 16:43:37 +02:00
										 |  |  |                                        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-10-12 17:27:29 +02:00
										 |  |  |   if (node == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   this = SPA_CONTAINER_OF (node, SpaALSASink, node); | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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, | 
					
						
							| 
									
										
										
										
											2017-03-07 11:56:43 +01:00
										 |  |  |                                 uint32_t      *n_input_ports, | 
					
						
							|  |  |  |                                 uint32_t      *max_input_ports, | 
					
						
							|  |  |  |                                 uint32_t      *n_output_ports, | 
					
						
							|  |  |  |                                 uint32_t      *max_output_ports) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   if (node == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (n_input_ports) | 
					
						
							|  |  |  |     *n_input_ports = 1; | 
					
						
							|  |  |  |   if (max_input_ports) | 
					
						
							|  |  |  |     *max_input_ports = 1; | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  |   if (n_output_ports) | 
					
						
							|  |  |  |     *n_output_ports = 0; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   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, | 
					
						
							| 
									
										
										
										
											2017-03-07 11:56:43 +01:00
										 |  |  |                                  uint32_t       n_input_ports, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                  uint32_t      *input_ids, | 
					
						
							| 
									
										
										
										
											2017-03-07 11:56:43 +01:00
										 |  |  |                                  uint32_t       n_output_ports, | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |                                  uint32_t      *output_ids) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   if (node == 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, | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  |                              SpaDirection    direction, | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |                              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-10-03 19:43:42 +02:00
										 |  |  |                                 SpaDirection    direction, | 
					
						
							| 
									
										
										
										
											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-10-03 19:43:42 +02:00
										 |  |  |                                       SpaDirection     direction, | 
					
						
							| 
									
										
										
										
											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, | 
					
						
							| 
									
										
										
										
											2017-03-07 11:56:43 +01:00
										 |  |  |                                       uint32_t         index) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   SpaALSASink *this; | 
					
						
							| 
									
										
										
										
											2017-02-24 09:28:18 +01:00
										 |  |  |   SpaResult res; | 
					
						
							|  |  |  |   SpaFormat *fmt; | 
					
						
							|  |  |  |   uint8_t buffer[1024]; | 
					
						
							| 
									
										
										
										
											2017-03-01 14:07:02 +01:00
										 |  |  |   SpaPODBuilder b = { NULL, }; | 
					
						
							| 
									
										
										
										
											2017-03-07 19:40:51 +01:00
										 |  |  |   SpaPODFrame f[2]; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-01 08:58:21 +01:00
										 |  |  |   if (node == NULL || format == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   this = SPA_CONTAINER_OF (node, SpaALSASink, node); | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  |   if (!CHECK_PORT (this, direction, port_id)) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 14:07:02 +01:00
										 |  |  | next: | 
					
						
							|  |  |  |   spa_pod_builder_init (&b, buffer, sizeof (buffer)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (index++) { | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     case 0: | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |       spa_pod_builder_format (&b, &f[0], this->type.format, | 
					
						
							|  |  |  |         this->type.media_type.audio, this->type.media_subtype.raw, | 
					
						
							| 
									
										
										
										
											2017-03-24 13:11:57 +01:00
										 |  |  |         PROP_U_EN (&f[1], this->type.format_audio.format,   SPA_POD_TYPE_ID,  3, this->type.audio_format.S16, | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |                                                                               this->type.audio_format.S16, | 
					
						
							|  |  |  |                                                                               this->type.audio_format.S32), | 
					
						
							| 
									
										
										
										
											2017-03-24 13:11:57 +01:00
										 |  |  |         PROP_U_MM (&f[1], this->type.format_audio.rate,     SPA_POD_TYPE_INT, 44100, 1, INT32_MAX), | 
					
						
							|  |  |  |         PROP_U_MM (&f[1], this->type.format_audio.channels, SPA_POD_TYPE_INT, 2,     1, INT32_MAX)); | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |       break; | 
					
						
							|  |  |  |     case 1: | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |       spa_pod_builder_format (&b, &f[0], this->type.format, | 
					
						
							|  |  |  |         this->type.media_type.audio, this->type.media_subtype_audio.aac, | 
					
						
							| 
									
										
										
										
											2017-03-22 10:04:24 +01:00
										 |  |  |         SPA_POD_TYPE_NONE); | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return SPA_RESULT_ENUM_END; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-03-17 11:58:09 +01:00
										 |  |  |   fmt = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaFormat); | 
					
						
							| 
									
										
										
										
											2017-02-24 09:28:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 14:07:02 +01:00
										 |  |  |   spa_pod_builder_init (&b, this->format_buffer, sizeof (this->format_buffer)); | 
					
						
							| 
									
										
										
										
											2017-02-24 09:28:18 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if ((res = spa_format_filter (fmt, filter, &b)) != SPA_RESULT_OK) | 
					
						
							| 
									
										
										
										
											2017-03-01 14:07:02 +01:00
										 |  |  |     goto next; | 
					
						
							| 
									
										
										
										
											2017-02-24 09:28:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-17 11:58:09 +01:00
										 |  |  |   *format = SPA_POD_BUILDER_DEREF (&b, 0, SpaFormat); | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  | static SpaResult | 
					
						
							|  |  |  | spa_alsa_clear_buffers (SpaALSASink *this) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (this->n_buffers > 0) { | 
					
						
							| 
									
										
										
										
											2016-11-09 12:57:51 +01:00
										 |  |  |     spa_list_init (&this->ready); | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |     this->n_buffers = 0; | 
					
						
							| 
									
										
										
										
											2016-11-03 19:41:53 +01:00
										 |  |  |     this->ringbuffer = NULL; | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_port_set_format (SpaNode            *node, | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  |                                     SpaDirection        direction, | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2017-03-17 11:58:09 +01:00
										 |  |  |   SpaPODBuilder b = { NULL }; | 
					
						
							|  |  |  |   SpaPODFrame f[2]; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   if (node == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   this = SPA_CONTAINER_OF (node, SpaALSASink, node); | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  |   if (!CHECK_PORT (this, direction, port_id)) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (format == NULL) { | 
					
						
							| 
									
										
										
										
											2016-11-03 19:41:53 +01:00
										 |  |  |     spa_log_info (this->log, "clear format"); | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |     spa_alsa_pause (this, false); | 
					
						
							|  |  |  |     spa_alsa_clear_buffers (this); | 
					
						
							|  |  |  |     spa_alsa_close (this); | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     this->have_format = false; | 
					
						
							| 
									
										
										
										
											2017-03-24 18:11:11 +01:00
										 |  |  |   } else { | 
					
						
							|  |  |  |     SpaAudioInfo info = { SPA_FORMAT_MEDIA_TYPE (format), | 
					
						
							|  |  |  |                           SPA_FORMAT_MEDIA_SUBTYPE (format), }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (info.media_type != this->type.media_type.audio || | 
					
						
							|  |  |  |         info.media_subtype != this->type.media_subtype.raw) | 
					
						
							|  |  |  |       return SPA_RESULT_INVALID_MEDIA_TYPE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!spa_format_audio_raw_parse (format, &info.info.raw, &this->type.format_audio)) | 
					
						
							|  |  |  |       return SPA_RESULT_INVALID_MEDIA_TYPE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (spa_alsa_set_format (this, &info, flags) < 0) | 
					
						
							|  |  |  |       return SPA_RESULT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this->current_format = info; | 
					
						
							|  |  |  |     this->have_format = true; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-24 18:11:11 +01:00
										 |  |  |   if (this->have_format) { | 
					
						
							|  |  |  |     this->info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS | | 
					
						
							|  |  |  |                        SPA_PORT_INFO_FLAG_LIVE; | 
					
						
							|  |  |  |     this->info.maxbuffering = this->buffer_frames * this->frame_size; | 
					
						
							|  |  |  |     this->info.latency = (this->period_frames * SPA_NSEC_PER_SEC) / this->rate; | 
					
						
							|  |  |  |     this->info.n_params = 3; | 
					
						
							|  |  |  |     this->info.params = this->params; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     spa_pod_builder_init (&b, this->params_buffer, sizeof (this->params_buffer)); | 
					
						
							|  |  |  |     spa_pod_builder_object (&b, &f[0], 0, this->type.alloc_param_buffers.Buffers, | 
					
						
							|  |  |  |         PROP    (&f[1], this->type.alloc_param_buffers.size,    SPA_POD_TYPE_INT, this->period_frames * this->frame_size), | 
					
						
							|  |  |  |         PROP    (&f[1], this->type.alloc_param_buffers.stride,  SPA_POD_TYPE_INT, 0), | 
					
						
							|  |  |  |         PROP_MM (&f[1], this->type.alloc_param_buffers.buffers, SPA_POD_TYPE_INT, 32, 1, 32), | 
					
						
							|  |  |  |         PROP    (&f[1], this->type.alloc_param_buffers.align,   SPA_POD_TYPE_INT, 16)); | 
					
						
							|  |  |  |     this->params[0] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaAllocParam); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     spa_pod_builder_object (&b, &f[0], 0, this->type.alloc_param_meta_enable.MetaEnable, | 
					
						
							|  |  |  |         PROP    (&f[1], this->type.alloc_param_meta_enable.type, SPA_POD_TYPE_INT, SPA_META_TYPE_HEADER)); | 
					
						
							|  |  |  |     this->params[1] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaAllocParam); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     spa_pod_builder_object (&b, &f[0], 0, this->type.alloc_param_meta_enable.MetaEnable, | 
					
						
							|  |  |  |         PROP    (&f[1], this->type.alloc_param_meta_enable.type, SPA_POD_TYPE_INT, SPA_META_TYPE_RINGBUFFER), | 
					
						
							|  |  |  |         PROP    (&f[1], this->type.alloc_param_meta_enable.ringbufferSize,   SPA_POD_TYPE_INT, this->period_frames * this->frame_size * 32), | 
					
						
							|  |  |  |         PROP    (&f[1], this->type.alloc_param_meta_enable.ringbufferStride, SPA_POD_TYPE_INT, 0), | 
					
						
							|  |  |  |         PROP    (&f[1], this->type.alloc_param_meta_enable.ringbufferBlocks, SPA_POD_TYPE_INT, 1), | 
					
						
							|  |  |  |         PROP    (&f[1], this->type.alloc_param_meta_enable.ringbufferAlign,  SPA_POD_TYPE_INT, 16)); | 
					
						
							|  |  |  |     this->params[2] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaAllocParam); | 
					
						
							|  |  |  |     this->info.extra = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     update_state (this, SPA_NODE_STATE_READY); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     update_state (this, SPA_NODE_STATE_CONFIGURE); | 
					
						
							| 
									
										
										
										
											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_get_format (SpaNode          *node, | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  |                                     SpaDirection      direction, | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2017-03-30 17:30:28 +02:00
										 |  |  |   SpaPODBuilder b = { NULL, }; | 
					
						
							|  |  |  |   SpaPODFrame f[2]; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   if (node == NULL || format == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   this = SPA_CONTAINER_OF (node, SpaALSASink, node); | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  |   if (!CHECK_PORT (this, direction, port_id)) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!this->have_format) | 
					
						
							|  |  |  |     return SPA_RESULT_NO_FORMAT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-30 17:30:28 +02:00
										 |  |  |   spa_pod_builder_init (&b, this->format_buffer, sizeof (this->format_buffer)); | 
					
						
							|  |  |  |   spa_pod_builder_format (&b, &f[0], this->type.format, | 
					
						
							|  |  |  |          this->type.media_type.audio, this->type.media_subtype.raw, | 
					
						
							|  |  |  |          PROP (&f[1], this->type.format_audio.format,   SPA_POD_TYPE_ID,  this->current_format.info.raw.format), | 
					
						
							|  |  |  |          PROP (&f[1], this->type.format_audio.rate,     SPA_POD_TYPE_INT, this->current_format.info.raw.rate), | 
					
						
							|  |  |  |          PROP (&f[1], this->type.format_audio.channels, SPA_POD_TYPE_INT, this->current_format.info.raw.channels)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   *format = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaFormat); | 
					
						
							| 
									
										
										
										
											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_get_info (SpaNode            *node, | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  |                                   SpaDirection        direction, | 
					
						
							| 
									
										
										
										
											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-10-12 17:27:29 +02:00
										 |  |  |   if (node == NULL || info == NULL) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   this = SPA_CONTAINER_OF (node, SpaALSASink, node); | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  |   if (!CHECK_PORT (this, direction, port_id)) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |     return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   *info = &this->info; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  | spa_alsa_sink_node_port_get_props (SpaNode       *node, | 
					
						
							|  |  |  |                                    SpaDirection   direction, | 
					
						
							|  |  |  |                                    uint32_t       port_id, | 
					
						
							|  |  |  |                                    SpaProps     **props) | 
					
						
							| 
									
										
										
										
											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_port_set_props (SpaNode         *node, | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  |                                    SpaDirection     direction, | 
					
						
							| 
									
										
										
										
											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-10-03 19:43:42 +02:00
										 |  |  |                                      SpaDirection     direction, | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |   SpaALSASink *this; | 
					
						
							|  |  |  |   int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (node == NULL) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!CHECK_PORT (this, direction, port_id)) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   this = SPA_CONTAINER_OF (node, SpaALSASink, node); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-03 19:41:53 +01:00
										 |  |  |   spa_log_info (this->log, "use buffers %d", n_buffers); | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (!this->have_format) | 
					
						
							|  |  |  |     return SPA_RESULT_NO_FORMAT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (n_buffers == 0) { | 
					
						
							|  |  |  |     spa_alsa_pause (this, false); | 
					
						
							|  |  |  |     spa_alsa_clear_buffers (this); | 
					
						
							|  |  |  |     update_state (this, SPA_NODE_STATE_READY); | 
					
						
							|  |  |  |     return SPA_RESULT_OK; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (i = 0; i < n_buffers; i++) { | 
					
						
							|  |  |  |     SpaALSABuffer *b = &this->buffers[i]; | 
					
						
							|  |  |  |     b->outbuf = buffers[i]; | 
					
						
							|  |  |  |     b->outstanding = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     b->h = spa_buffer_find_meta (b->outbuf, SPA_META_TYPE_HEADER); | 
					
						
							| 
									
										
										
										
											2016-11-03 19:41:53 +01:00
										 |  |  |     b->rb = spa_buffer_find_meta (b->outbuf, SPA_META_TYPE_RINGBUFFER); | 
					
						
							|  |  |  |     if (b->rb) | 
					
						
							|  |  |  |       this->ringbuffer = b; | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     switch (buffers[i]->datas[0].type) { | 
					
						
							|  |  |  |       case SPA_DATA_TYPE_MEMFD: | 
					
						
							|  |  |  |       case SPA_DATA_TYPE_DMABUF: | 
					
						
							|  |  |  |       case SPA_DATA_TYPE_MEMPTR: | 
					
						
							|  |  |  |         if (buffers[i]->datas[0].data == NULL) { | 
					
						
							| 
									
										
										
										
											2016-11-03 19:41:53 +01:00
										 |  |  |           spa_log_error (this->log, "alsa-source: need mapped memory"); | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   this->n_buffers = n_buffers; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   update_state (this, SPA_NODE_STATE_PAUSED); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							| 
									
										
										
										
											2016-07-08 20:12:56 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | spa_alsa_sink_node_port_alloc_buffers (SpaNode         *node, | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  |                                        SpaDirection     direction, | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   if (node == NULL || buffers == NULL) | 
					
						
							| 
									
										
										
										
											2016-08-24 16:26:58 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  |   if (!CHECK_PORT (this, direction, port_id)) | 
					
						
							| 
									
										
										
										
											2016-08-24 16:26:58 +02:00
										 |  |  |     return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   this = SPA_CONTAINER_OF (node, SpaALSASink, node); | 
					
						
							| 
									
										
										
										
											2016-08-24 16:26:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (!this->have_format) | 
					
						
							|  |  |  |     return SPA_RESULT_NO_FORMAT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 18:18:59 +02:00
										 |  |  |   return SPA_RESULT_NOT_IMPLEMENTED; | 
					
						
							| 
									
										
										
										
											2016-07-08 20:12:56 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2017-04-03 14:56:04 +02:00
										 |  |  | spa_alsa_sink_node_port_set_io (SpaNode      *node, | 
					
						
							|  |  |  |                                 SpaDirection  direction, | 
					
						
							|  |  |  |                                 uint32_t      port_id, | 
					
						
							|  |  |  |                                 SpaPortIO    *io) | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   SpaALSASink *this; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 18:23:09 +01:00
										 |  |  |   if (node == NULL) | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 17:27:29 +02:00
										 |  |  |   this = SPA_CONTAINER_OF (node, SpaALSASink, node); | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-03 14:56:04 +02:00
										 |  |  |   if (!CHECK_PORT (this, direction, port_id)) | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  |     return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-03 14:56:04 +02:00
										 |  |  |   this->io = io; | 
					
						
							| 
									
										
										
										
											2016-08-02 16:34:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  | static SpaResult | 
					
						
							|  |  |  | spa_alsa_sink_node_port_reuse_buffer (SpaNode         *node, | 
					
						
							|  |  |  |                                       uint32_t         port_id, | 
					
						
							|  |  |  |                                       uint32_t         buffer_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return SPA_RESULT_NOT_IMPLEMENTED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							| 
									
										
										
										
											2016-10-21 14:57:01 +02:00
										 |  |  | spa_alsa_sink_node_port_send_command (SpaNode          *node, | 
					
						
							|  |  |  |                                       SpaDirection      direction, | 
					
						
							|  |  |  |                                       uint32_t          port_id, | 
					
						
							| 
									
										
										
										
											2017-03-22 10:04:24 +01:00
										 |  |  |                                       SpaCommand       *command) | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |   SpaALSASink *this; | 
					
						
							|  |  |  |   SpaResult res; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (node == NULL) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   this = SPA_CONTAINER_OF (node, SpaALSASink, node); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (port_id != 0) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |   if (SPA_COMMAND_TYPE (command) == this->type.command_node.Pause) { | 
					
						
							| 
									
										
										
										
											2017-03-22 10:04:24 +01:00
										 |  |  |     if (SPA_RESULT_IS_OK (res = spa_alsa_pause (this, false))) { | 
					
						
							|  |  |  |       update_state (this, SPA_NODE_STATE_PAUSED); | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-03-22 10:04:24 +01:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |   else if (SPA_COMMAND_TYPE (command) == this->type.command_node.Start) { | 
					
						
							| 
									
										
										
										
											2017-03-22 10:04:24 +01:00
										 |  |  |     if (SPA_RESULT_IS_OK (res = spa_alsa_start (this, false))) { | 
					
						
							|  |  |  |       update_state (this, SPA_NODE_STATE_STREAMING); | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-03-22 10:04:24 +01:00
										 |  |  |   else | 
					
						
							|  |  |  |     res = SPA_RESULT_NOT_IMPLEMENTED; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |   return res; | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 18:23:09 +01:00
										 |  |  | static SpaResult | 
					
						
							|  |  |  | spa_alsa_sink_node_process_input (SpaNode *node) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   SpaALSASink *this; | 
					
						
							| 
									
										
										
										
											2017-04-03 14:56:04 +02:00
										 |  |  |   SpaPortIO *input; | 
					
						
							| 
									
										
										
										
											2016-11-07 18:23:09 +01:00
										 |  |  |   SpaALSABuffer *b; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (node == NULL) | 
					
						
							|  |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   this = SPA_CONTAINER_OF (node, SpaALSASink, node); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ((input = this->io) == NULL) | 
					
						
							|  |  |  |     return SPA_RESULT_OK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!this->have_format) { | 
					
						
							|  |  |  |     input->status = SPA_RESULT_NO_FORMAT; | 
					
						
							|  |  |  |     return SPA_RESULT_ERROR; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (input->buffer_id >= this->n_buffers) { | 
					
						
							|  |  |  |     input->status = SPA_RESULT_INVALID_BUFFER_ID; | 
					
						
							|  |  |  |     return SPA_RESULT_ERROR; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   b = &this->buffers[input->buffer_id]; | 
					
						
							|  |  |  |   if (!b->outstanding) { | 
					
						
							| 
									
										
										
										
											2017-01-18 18:29:15 +01:00
										 |  |  |     input->buffer_id = SPA_ID_INVALID; | 
					
						
							| 
									
										
										
										
											2016-11-07 18:23:09 +01:00
										 |  |  |     input->status = SPA_RESULT_INVALID_BUFFER_ID; | 
					
						
							|  |  |  |     return SPA_RESULT_ERROR; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (this->ringbuffer) { | 
					
						
							|  |  |  |     this->ringbuffer->outstanding = true; | 
					
						
							|  |  |  |     this->ringbuffer = b; | 
					
						
							|  |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2016-12-20 18:10:50 +01:00
										 |  |  |     spa_list_insert (this->ready.prev, &b->link); | 
					
						
							| 
									
										
										
										
											2017-04-03 14:56:04 +02:00
										 |  |  |     spa_log_trace (this->log, "alsa-sink %p: queue buffer %u", this, input->buffer_id); | 
					
						
							| 
									
										
										
										
											2016-11-07 18:23:09 +01:00
										 |  |  |   } | 
					
						
							|  |  |  |   b->outstanding = false; | 
					
						
							| 
									
										
										
										
											2017-01-18 18:29:15 +01:00
										 |  |  |   input->buffer_id = SPA_ID_INVALID; | 
					
						
							| 
									
										
										
										
											2016-11-07 18:23:09 +01:00
										 |  |  |   input->status = SPA_RESULT_OK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return SPA_RESULT_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							|  |  |  | spa_alsa_sink_node_process_output (SpaNode *node) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return SPA_RESULT_INVALID_PORT; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | static const SpaNode alsasink_node = { | 
					
						
							|  |  |  |   sizeof (SpaNode), | 
					
						
							| 
									
										
										
										
											2016-09-15 17:51:34 +02:00
										 |  |  |   NULL, | 
					
						
							| 
									
										
										
										
											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, | 
					
						
							| 
									
										
										
										
											2017-04-03 14:56:04 +02:00
										 |  |  |   spa_alsa_sink_node_port_set_io, | 
					
						
							| 
									
										
										
										
											2016-10-03 19:43:42 +02:00
										 |  |  |   spa_alsa_sink_node_port_reuse_buffer, | 
					
						
							| 
									
										
										
										
											2016-10-21 14:57:01 +02:00
										 |  |  |   spa_alsa_sink_node_port_send_command, | 
					
						
							| 
									
										
										
										
											2016-11-07 18:23:09 +01:00
										 |  |  |   spa_alsa_sink_node_process_input, | 
					
						
							|  |  |  |   spa_alsa_sink_node_process_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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |   if (interface_id == this->type.node) | 
					
						
							| 
									
										
										
										
											2016-10-07 13:14:32 +02:00
										 |  |  |     *interface = &this->node; | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     return SPA_RESULT_UNKNOWN_INTERFACE; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  |   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, | 
					
						
							| 
									
										
										
										
											2016-09-15 11:49:34 +02:00
										 |  |  |                 SpaHandle               *handle, | 
					
						
							| 
									
										
										
										
											2016-10-05 17:43:11 +02:00
										 |  |  |                 const SpaDict           *info, | 
					
						
							| 
									
										
										
										
											2016-10-07 13:14:32 +02:00
										 |  |  |                 const SpaSupport        *support, | 
					
						
							| 
									
										
										
										
											2017-03-07 11:56:43 +01:00
										 |  |  |                 uint32_t                 n_support) | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   SpaALSASink *this; | 
					
						
							| 
									
										
										
										
											2017-03-07 11:56:43 +01:00
										 |  |  |   uint32_t i; | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-10-07 13:14:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   for (i = 0; i < n_support; i++) { | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |     if (strcmp (support[i].type, SPA_TYPE__TypeMap) == 0) | 
					
						
							| 
									
										
										
										
											2016-10-07 13:14:32 +02:00
										 |  |  |       this->map = support[i].data; | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |     else if (strcmp (support[i].type, SPA_TYPE__Log) == 0) | 
					
						
							| 
									
										
										
										
											2016-10-07 13:14:32 +02:00
										 |  |  |       this->log = support[i].data; | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |     else if (strcmp (support[i].type, SPA_TYPE_LOOP__DataLoop) == 0) | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |       this->data_loop = support[i].data; | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |     else if (strcmp (support[i].type, SPA_TYPE_LOOP__MainLoop) == 0) | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |       this->main_loop = support[i].data; | 
					
						
							| 
									
										
										
										
											2016-10-07 13:14:32 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   if (this->map == NULL) { | 
					
						
							| 
									
										
										
										
											2017-04-03 14:56:04 +02:00
										 |  |  |     spa_log_error (this->log, "a type-map is needed"); | 
					
						
							|  |  |  |     return SPA_RESULT_ERROR; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (this->data_loop == NULL) { | 
					
						
							|  |  |  |     spa_log_error (this->log, "a data loop is needed"); | 
					
						
							|  |  |  |     return SPA_RESULT_ERROR; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (this->main_loop == NULL) { | 
					
						
							|  |  |  |     spa_log_error (this->log, "a main loop is needed"); | 
					
						
							| 
									
										
										
										
											2016-10-07 13:14:32 +02:00
										 |  |  |     return SPA_RESULT_ERROR; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-03-24 11:40:58 +01:00
										 |  |  |   init_type (&this->type, this->map); | 
					
						
							| 
									
										
										
										
											2016-10-07 13:14:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-30 20:35:34 +02:00
										 |  |  |   this->node = alsasink_node; | 
					
						
							| 
									
										
										
										
											2016-09-19 09:16:58 +02:00
										 |  |  |   this->stream = SND_PCM_STREAM_PLAYBACK; | 
					
						
							| 
									
										
										
										
											2017-02-28 10:48:53 +01:00
										 |  |  |   reset_alsa_sink_props (&this->props); | 
					
						
							| 
									
										
										
										
											2016-06-28 12:21:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-09 12:57:51 +01:00
										 |  |  |   spa_list_init (&this->ready); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |   for (i = 0; info && i < info->n_items; i++) { | 
					
						
							|  |  |  |     if (!strcmp (info->items[i].key, "alsa.card")) { | 
					
						
							| 
									
										
										
										
											2017-02-28 10:48:53 +01:00
										 |  |  |       snprintf (this->props.device, 63, "hw:%s", info->items[i].value); | 
					
						
							| 
									
										
										
										
											2016-10-28 16:56:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-07-13 18:29:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-26 17:27:04 +02:00
										 |  |  |   update_state (this, SPA_NODE_STATE_CONFIGURE); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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[] = | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-03-23 21:15:52 +01:00
										 |  |  |   { SPA_TYPE__Node, }, | 
					
						
							| 
									
										
										
										
											2016-07-13 18:29:55 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SpaResult | 
					
						
							|  |  |  | alsa_sink_enum_interface_info (const SpaHandleFactory  *factory, | 
					
						
							| 
									
										
										
										
											2016-07-15 18:22:29 +02:00
										 |  |  |                                const SpaInterfaceInfo **info, | 
					
						
							| 
									
										
										
										
											2017-03-07 11:56:43 +01:00
										 |  |  |                                uint32_t                 index) | 
					
						
							| 
									
										
										
										
											2016-07-13 18:29:55 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-02-01 08:58:21 +01:00
										 |  |  |   if (factory == NULL || info == NULL) | 
					
						
							| 
									
										
										
										
											2016-07-15 18:22:29 +02:00
										 |  |  |     return SPA_RESULT_INVALID_ARGUMENTS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (index) { | 
					
						
							|  |  |  |     case 0: | 
					
						
							|  |  |  |       *info = &alsa_sink_interfaces[index]; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return SPA_RESULT_ENUM_END; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											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, | 
					
						
							|  |  |  | }; |