root/branches/libfreebob-1.0/src/libfreebobstreaming/freebob_connections.c

Revision 513, 9.5 kB (checked in by ppalmers, 17 years ago)

- renumber the midi location parameters to fix bogus values returned

by AV/C discovery

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  *   FreeBoB Streaming API
3  *   FreeBoB = Firewire (pro-)audio for linux
4  *
5  *   http://freebob.sf.net
6  *
7  *   Copyright (C) 2005 Pieter Palmers <pieterpalmers@users.sourceforge.net>
8  *
9  *   This program is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU General Public License as published by
11  *   the Free Software Foundation; either version 2 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This program is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with this program; if not, write to the Free Software
21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  *
24  *
25  */
26
27 /* freebob_connections.c
28  *
29  * Connection handling
30  *
31  */
32 #include <libraw1394/raw1394.h>
33 #include <libiec61883/iec61883.h>
34
35 #include "libfreebob/freebob_streaming.h"
36 #include "freebob_streaming_private.h"
37 #include "freebob_connections.h"
38 #include "freebob_debug.h"
39
40 raw1394handle_t freebob_open_raw1394 (int port)
41 {
42         raw1394handle_t raw1394_handle;
43         int ret;
44         int stale_port_info;
45  
46         /* open the connection to libraw1394 */
47         raw1394_handle = raw1394_new_handle ();
48         if (!raw1394_handle) {
49                 if (errno == 0) {
50                         printError("This version of libraw1394 is "
51                                     "incompatible with your kernel\n");
52                 } else {
53                         printError("Could not create libraw1394 "
54                                     "handle: %s\n", strerror (errno));
55                 }
56
57                 return NULL;
58         }
59  
60         /* set the port we'll be using */
61         stale_port_info = 1;
62         do {
63                 ret = raw1394_get_port_info (raw1394_handle, NULL, 0);
64                 if (ret <= port) {
65                         printError("IEEE394 port %d is not available\n", port);
66                         raw1394_destroy_handle (raw1394_handle);
67                         return NULL;
68                 }
69  
70                 ret = raw1394_set_port (raw1394_handle, port);
71                 if (ret == -1) {
72                         if (errno != ESTALE) {
73                                 printError("Couldn't use IEEE394 port %d: %s\n",
74                                             port, strerror (errno));
75                                 raw1394_destroy_handle (raw1394_handle);
76                                 return NULL;
77                         }
78                 }
79                 else {
80                         stale_port_info = 0;
81                 }
82         } while (stale_port_info);
83  
84         return raw1394_handle;
85 }
86
87 int freebob_streaming_reset_connection(freebob_device_t * dev, freebob_connection_t *connection) {
88         int s=0;
89         int err=0;
90        
91         assert(dev);
92         assert(connection);
93        
94         printEnter();
95        
96         for (s=0;s<connection->nb_streams;s++) {
97                 err=freebob_streaming_reset_stream(dev,&connection->streams[s]);
98                 if(err) {
99                         printError("Could not reset stream %d",s);
100                         break;
101                 }
102                
103         }
104        
105         // reset the event buffer, discard all content
106         freebob_ringbuffer_reset(connection->event_buffer);
107        
108         // reset the timestamp buffer, discard all content
109         freebob_ringbuffer_reset(connection->timestamp_buffer);
110        
111         // reset the event counter
112         connection->status.events=0;
113        
114         // reset the boundary counter
115         connection->status.frames_left = 0;
116        
117         // reset the counters
118         connection->status.xruns = 0;
119         connection->status.packets=0;   
120
121 #ifdef DEBUG
122         connection->status.total_packets_prev=0;
123 #endif
124
125         connection->status.dropped=0;
126
127         // make sure the connection is polled next time
128         if(connection->pfd) { // this can be called before everything is init'ed
129                 connection->pfd->events=POLLIN;
130         }
131
132         printExit();
133        
134         return 0;
135        
136 }
137
138 int freebob_streaming_init_connection(freebob_device_t * dev, freebob_connection_t *connection) {
139         int err=0;
140         int s=0;
141        
142         connection->status.frames_left=0;
143        
144         connection->parent=dev;
145                
146         // create raw1394 handles
147         connection->raw_handle=freebob_open_raw1394(connection->spec.port);
148         if (!connection->raw_handle) {
149                 printError("Could not get raw1394 handle\n");
150                 return -ENOMEM;
151         }
152         raw1394_set_userdata(connection->raw_handle, (void *)connection);
153        
154         connection->iso.speed = RAW1394_ISO_SPEED_400;
155        
156         connection->iso.bandwidth=-1;
157         connection->iso.startcycle=-1;
158        
159         // allocate the event ringbuffer
160         if( !(connection->event_buffer=freebob_ringbuffer_create(
161                         (connection->spec.dimension * dev->options.nb_buffers * dev->options.period_size) * sizeof(quadlet_t)))) {
162                 printError("Could not allocate memory event ringbuffer");
163                 return -ENOMEM;
164                        
165         }
166         // allocate the temporary cluster buffer
167         if( !(connection->cluster_buffer=(char *)calloc(connection->spec.dimension,sizeof(quadlet_t)))) {
168                 printError("Could not allocate temporary cluster buffer");
169                 freebob_ringbuffer_free(connection->event_buffer);
170                 return -ENOMEM;
171         }
172        
173         // allocate the timestamp buffer
174         if( !(connection->timestamp_buffer=freebob_ringbuffer_create(TIMESTAMP_BUFFER_SIZE * sizeof(freebob_timestamp_t)))) {
175                 printError("Could not allocate timestamp ringbuffer");
176                 freebob_ringbuffer_free(connection->event_buffer);
177                 free(connection->cluster_buffer);
178                 return -ENOMEM;
179         }
180        
181         connection->total_delay=0;
182        
183         /*
184          * init the streams this connection is composed of
185          */
186         assert(connection->spec.stream_info);
187         connection->nb_streams=connection->spec.stream_info->nb_streams;
188        
189         connection->streams=calloc(connection->nb_streams, sizeof(freebob_stream_t));
190        
191         if(!connection->streams) {
192                 printError("Could not allocate memory for streams");
193                 free(connection->cluster_buffer);
194                 freebob_ringbuffer_free(connection->event_buffer);
195                 return -ENOMEM;
196         }
197                
198         err=0;
199         int midi_channel=0;
200         for (s=0;s<connection->nb_streams;s++) {
201                 err=freebob_streaming_init_stream(dev,&connection->streams[s],connection->spec.stream_info->streams[s]);
202                 if(err) {
203                         printError("Could not init stream %d",s);
204                         break;
205                 }
206                
207                 // set the stream parent relation
208                 connection->streams[s].parent=connection;
209                
210                 // register the stream in the stream list used for reading out
211                 if(connection->spec.direction==FREEBOB_CAPTURE) {
212                         freebob_streaming_register_capture_stream(dev, &connection->streams[s]);
213                 } else {
214                         freebob_streaming_register_playback_stream(dev, &connection->streams[s]);
215                 }
216         }       
217         if (err) {
218                 debugPrint(DEBUG_LEVEL_STARTUP,"  Cleaning up streams...\n");
219                 while(s--) { // TODO: check if this counts correctly
220                         debugPrint(DEBUG_LEVEL_STARTUP,"  Cleaning up stream %d...\n",s);
221                         freebob_streaming_cleanup_stream(dev, &connection->streams[s]);
222                 }
223                
224                 free(connection->streams);
225                 free(connection->cluster_buffer);
226                 freebob_ringbuffer_free(connection->event_buffer);
227                 freebob_ringbuffer_free(connection->timestamp_buffer);
228                
229                 return err;             
230         }
231        
232         // FIXME: a flaw of the current approach is that a spec->stream_info isn't a valid pointer
233         connection->spec.stream_info=NULL;
234        
235         // put the connection into a know state
236         freebob_streaming_reset_connection(dev, connection);
237
238         return 0;
239 }
240
241 int freebob_streaming_cleanup_connection(freebob_device_t * dev, freebob_connection_t *connection) {
242
243         unsigned int s;
244        
245         for (s=0;s<connection->nb_streams;s++) {
246                 debugPrint(DEBUG_LEVEL_STARTUP,"  Cleaning up stream %d...\n",s);
247                 freebob_streaming_cleanup_stream(dev, &connection->streams[s]);
248         }
249        
250         free(connection->streams);
251         free(connection->cluster_buffer);
252         freebob_ringbuffer_free(connection->event_buffer);
253         freebob_ringbuffer_free(connection->timestamp_buffer);
254        
255         raw1394_destroy_handle(connection->raw_handle);
256 /*
257         assert(connection->status.packet_info_table);
258         free(connection->status.packet_info_table);
259         connection->status.packet_info_table=NULL;
260 */
261        
262         return 0;
263        
264 }
265
266 /**
267  * Initializes a stream_t based upon an stream_info_t
268  */
269 int freebob_streaming_init_stream(freebob_device_t* dev, freebob_stream_t *dst, freebob_stream_spec_t *src) {
270         assert(dev);
271         assert(dst);
272         assert(src);
273        
274         memcpy(&dst->spec,src,sizeof(freebob_stream_spec_t));
275        
276         // allocate the ringbuffer
277         // the lock free ringbuffer needs one extra frame
278         // it can only be filled to size-1 bytes
279
280         // keep the ringbuffer aligned by adding sizeof(sample_t) bytes instead of just 1
281         int buffer_size_frames=dev->options.nb_buffers*dev->options.period_size+1;
282         dst->buffer=freebob_ringbuffer_create(buffer_size_frames*sizeof(freebob_sample_t));
283        
284        
285         // initialize the decoder stuff to use the per-stream read functions
286         dst->buffer_type=freebob_buffer_type_per_stream;
287         dst->user_buffer=NULL;
288        
289         // create any data structures for the decode buffers
290         freebob_streaming_set_stream_buffer(dev, dst, NULL, freebob_buffer_type_per_stream);
291        
292         // no other init needed
293         return 0;
294        
295 }
296
297 /**
298   * destroys a stream_t
299   */
300 void freebob_streaming_cleanup_stream(freebob_device_t* dev, freebob_stream_t *dst) {
301         assert(dev);
302         assert(dst);
303         assert(dst->user_buffer);
304        
305         freebob_streaming_free_stream_buffer(dev, dst);
306                
307         freebob_ringbuffer_free(dst->buffer);
308         return;
309        
310 }
311
312 /**
313   * puts a stream into a known state
314   */
315 int freebob_streaming_reset_stream(freebob_device_t* dev, freebob_stream_t *dst) {
316         assert(dev);
317         assert(dst);
318        
319         freebob_ringbuffer_reset(dst->buffer);
320         return 0;
321 }
322
323
324 int freebob_streaming_prefill_stream(freebob_device_t* dev, freebob_stream_t *stream) {
325         assert(stream);
326         int towrite=0;
327         int written=0;
328         char *buffer=NULL;
329                        
330         switch(stream->spec.format) {
331                 case IEC61883_STREAM_TYPE_MBLA:
332                         towrite=dev->options.period_size*dev->options.nb_buffers*sizeof(freebob_sample_t);
333                        
334                         // calloc clears the allocated memory
335                         buffer=calloc(1,towrite);
336                         written=freebob_ringbuffer_write(stream->buffer,(char *)buffer,towrite);
337                         free(buffer);
338                        
339                         if(written != towrite) {
340                                 assert(!"Could not prefill the playback stream ringbuffer, which should have been empty.");
341                                 printError("Could not prefill the buffer. Written (%d/%d) of (%d/%d) bytes/frames\n",
342                                         written,written/sizeof(freebob_sample_t),towrite,towrite/sizeof(freebob_sample_t));
343                                 return -1;
344                         }
345                 break;
346                 case IEC61883_STREAM_TYPE_MIDI: // no prefill nescessary
347                 case IEC61883_STREAM_TYPE_SPDIF: // unsupported
348                 default:
349                 break;
350         }
351         return 0;
352 }
Note: See TracBrowser for help on using the browser.