audio.c
Go to the documentation of this file.
1 /*
2  * This file is part of the OpenKinect Project. http://www.openkinect.org
3  *
4  * Copyright (c) 2011 individual OpenKinect contributors. See the CONTRIB file
5  * for details.
6  *
7  * This code is licensed to you under the terms of the Apache License, version
8  * 2.0, or, at your option, the terms of the GNU General Public License,
9  * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses,
10  * or the following URLs:
11  * http://www.apache.org/licenses/LICENSE-2.0
12  * http://www.gnu.org/licenses/gpl-2.0.txt
13  *
14  * If you redistribute this file in source form, modified or unmodified, you
15  * may:
16  * 1) Leave this header intact and distribute it under the same terms,
17  * accompanying it with the APACHE20 and GPL20 files, or
18  * 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or
19  * 3) Delete the GPL v2 clause and accompany it with the APACHE20 file
20  * In all cases you must keep the copyright notice intact and include a copy
21  * of the CONTRIB file.
22  *
23  * Binary distributions must follow the binary distribution requirements of
24  * either License.
25  */
26 #include "libfreenect.h"
27 #include "libfreenect_audio.h"
28 #include "freenect_internal.h"
29 
30 #include <string.h>
31 #include <stdlib.h>
32 
33 
34 static void prepare_iso_out_data(freenect_device* dev, uint8_t* buffer) {
35  audio_stream* stream = &dev->audio;
36  if (dev->audio_out_cb) {
37  // Then pull data from the ring buffer, calling the callback as needed to refill the buffer
38  } else {
39  memset(buffer, 0, 76);
40  }
41  ((uint16_t*)buffer)[0] = stream->out_window;
42  buffer[2] = stream->out_seq;
43  if (stream->out_window_parity == 0) {
44  if (stream->out_counter_within_window < 4) {
45  // madness type 1 - high nibble of buffer[3] should be the seq_in_window-th nibble of timestamp
46  buffer[3] = (((stream->out_weird_timestamp >> (stream->out_counter_within_window*4)) & 0x000f) << 4) | 0x05; // I have no idea why we do this.
47  } else if (stream->out_counter_within_window < 8) {
48  // madness type 2 - same thing mod 4, but we add 23 to weird_timestamp for no clear reason.
49  buffer[3] = ((((stream->out_weird_timestamp+23) >> ((stream->out_counter_within_window-4)*4)) & 0x000f) << 4) | 0x05; // I have even less idea why we do this.
50  } else {
51  buffer[3] = 0x01; // Oh, and then this.
52  }
53  } else {
54  if (stream->out_counter_within_window < 4) {
55  // madness type 1
56  buffer[3] = (((stream->out_weird_timestamp >> (stream->out_counter_within_window*4)) & 0x000f) << 4) | 0x05; // I have no idea why we do this.
57  } else {
58  buffer[3] = 0x01;
59  }
60  }
61  // Now, update the values for their next usage:
62  stream->out_seq++;
63  stream->out_counter_within_window++;
64  stream->out_weird_timestamp += (stream->out_window_parity == 1) ? 6 : 5;
65  switch(stream->out_seq) {
66  case 0x80:
67  stream->out_seq = 0;
68  // TODO: if we're at the beginning of a new outgoing window, save a timestamp
69  case 0x2b:
70  case 0x56:
71  stream->out_counter_within_window = 0;
72  stream->out_window++;
73  stream->out_window_parity++;
74  default:
75  break;
76  }
77  if (stream->out_window_parity == 3) stream->out_window_parity = 0;
78  return;
79 }
80 
81 static void iso_out_callback(freenect_device *dev, uint8_t *pkt, int len) {
82  prepare_iso_out_data(dev, pkt);
83 }
84 
85 static void iso_in_callback(freenect_device *dev, uint8_t *pkt, int len) {
86  freenect_context *ctx = dev->parent;
87  if (len == 524) { // Cool, this is audio data
88  audio_in_block* block = (audio_in_block*)pkt;
89  if (block->magic != 0x80000080) {
90  FN_ERROR("audio: invalid magic in iso IN packet: %08X\n", block->magic);
91  return;
92  }
93  if (block->window != dev->audio.in_window) {
94  FN_SPEW("audio: IN window changed: was %04X now %04X\n", dev->audio.in_window, block->window);
95  if (dev->audio_in_cb) {
96  dev->audio_in_cb(dev, 256, dev->audio.mic_buffer[0], dev->audio.mic_buffer[1],
97  dev->audio.mic_buffer[2], dev->audio.mic_buffer[3],
99  }
100  int t;
101  for(t = 0; t < 10; t++) {
102  if (dev->audio.last_seen_window[t] != dev->audio.in_window) {
103  FN_SPEW("audio: did not receive data for channel 0x%02x\n", t+1);
104  }
105  }
106  if (block->window - dev->audio.in_window > 3) {
107  FN_SPEW("audio: packet loss, dropped %d windows\n", (block->window - dev->audio.in_window - 3) / 3);
108  }
109  dev->audio.in_window = block->window;
110  }
111  switch(block->channel) {
112  case 1:
113  memcpy(dev->audio.cancelled_buffer, &block->samples, 512);
114  break;
115  case 2:
116  case 3:
117  case 4:
118  case 5:
119  case 6:
120  case 7:
121  case 8:
122  case 9:
123  if (block->channel & 1) {
124  memcpy(&(dev->audio.mic_buffer[(block->channel-2) / 2][128]), &block->samples, 512);
125  } else {
126  memcpy(dev->audio.mic_buffer[(block->channel-2) / 2], &block->samples, 512);
127  }
128  break;
129  default:
130  FN_ERROR("audio: invalid channel in iso IN packet: %d\n", block->channel);
131  break;
132  }
133  dev->audio.last_seen_window[block->channel-1] = block->window;
134 
135  } else if (len == 60) { // Then this is the uninterpreted signalling information
136 
137  } else if (len != 0) {
138  FN_ERROR("audio: received an iso IN packet of strange length: %d\n", len);
139  }
140 }
141 
143  dev->audio_in_cb = callback;
144 }
146  dev->audio_out_cb = callback;
147 }
148 
150  freenect_context *ctx = dev->parent;
151  int res;
152 
153  if (dev->audio.running)
154  return -1;
155 
156  // Allocate buffers
157  dev->audio.audio_out_ring = (freenect_sample_51*)malloc(256 * sizeof(freenect_sample_51));
158  memset(dev->audio.audio_out_ring, 0, 256 * sizeof(freenect_sample_51));
159  dev->audio.cancelled_buffer = (int16_t*)malloc(256*sizeof(int16_t));
160  memset(dev->audio.cancelled_buffer, 0, 256*sizeof(int16_t));
161  int i;
162  for(i = 0; i < 4; i++) {
163  dev->audio.mic_buffer[i] = (int32_t*)malloc(256*sizeof(int32_t));
164  memset(dev->audio.mic_buffer[i], 0, 256*sizeof(int32_t));
165  }
166  dev->audio.in_unknown = malloc(48); // amount of data in small transfer
167 
168  // Set initial parameter values
169  dev->audio.ring_reader_idx = 0;
170  dev->audio.ring_writer_idx = 0;
171  dev->audio.out_window = 0;
172  dev->audio.out_seq = 0;
174  dev->audio.out_weird_timestamp = 0;
175  dev->audio.out_window_parity = 0;
176  dev->audio.in_window = 0;
177  dev->audio.in_counter = 0;
178  for(i = 0; i < 10; i++) {
179  dev->audio.last_seen_window[i] = 0;
180  }
181 
182  // Start isochronous streams
184  if (res < 0) {
185  FN_ERROR("audio: failed to start isochronous IN stream: %d\n", res);
186  return res;
187  }
189  if (res < 0) {
190  FN_ERROR("audio: failed to start isochronous OUT stream: %d\n", res);
191  return res;
192  }
193 
194  dev->audio.running = 1;
195  return 0;
196 }
197 
199  freenect_context *ctx = dev->parent;
200  int res;
201  int ret = 0;
202 
203  if (!dev->audio.running)
204  return -1;
205 
206  // Stop isochronous transfers
207  // Note: I'm not sure how to make this work if there's partial failure.
208  dev->audio.running = 0;
209  res = fnusb_stop_iso(&dev->usb_audio, &dev->audio_in_isoc);
210  if (res < 0) {
211  FN_ERROR("audio: failed to stop isochronous IN stream: %d\n", res);
212  return res;
213  }
214  res = fnusb_stop_iso(&dev->usb_audio, &dev->audio_out_isoc);
215  if (res < 0) {
216  FN_ERROR("audio: failed to stop isochronous OUT stream: %d\n", res);
217  return res;
218  }
219 
220  // Free buffers
221  if (dev->audio.audio_out_ring)
222  free(dev->audio.audio_out_ring);
223  if (dev->audio.cancelled_buffer)
224  free(dev->audio.cancelled_buffer);
225  if (dev->audio.in_unknown)
226  free(dev->audio.in_unknown);
227 
228  int i;
229  for (i = 0; i < 4; i++) {
230  if (dev->audio.mic_buffer[i])
231  free(dev->audio.mic_buffer[i]);
232  dev->audio.mic_buffer[i] = NULL;
233  }
234 
235  dev->audio.audio_out_ring = NULL;
236  dev->audio.cancelled_buffer = NULL;
237  dev->audio.in_unknown = NULL;
238 
239  return ret;
240 }
void(* freenect_audio_in_cb)(freenect_device *dev, int num_samples, int32_t *mic1, int32_t *mic2, int32_t *mic3, int32_t *mic4, int16_t *cancelled, void *unknown)
void(* freenect_audio_out_cb)(freenect_device *dev, freenect_sample_51 *samples, int *sample_count)
freenect_context * parent
FN_INTERNAL int fnusb_start_iso(fnusb_dev *dev, fnusb_isoc_stream *strm, fnusb_iso_cb cb, int ep, int xfers, int pkts, int len)
Definition: usb_libusb10.c:755
uint8_t out_window_parity
short int16_t
static void iso_out_callback(freenect_device *dev, uint8_t *pkt, int len)
Definition: audio.c:81
unsigned short uint16_t
#define FN_ERROR(...)
FN_INTERNAL int fnusb_stop_iso(fnusb_dev *dev, fnusb_isoc_stream *strm)
Definition: usb_libusb10.c:793
unsigned char uint8_t
uint8_t out_counter_within_window
fnusb_isoc_stream audio_in_isoc
Structure to represent a single 16-bit signed little-endian PCM sample.
freenect_sample_51 * audio_out_ring
static void iso_in_callback(freenect_device *dev, uint8_t *pkt, int len)
Definition: audio.c:85
uint16_t out_weird_timestamp
void freenect_set_audio_in_callback(freenect_device *dev, freenect_audio_in_cb callback)
Definition: audio.c:142
int int32_t
void freenect_set_audio_out_callback(freenect_device *dev, freenect_audio_out_cb callback)
Definition: audio.c:145
#define FN_SPEW(...)
void(* callback)(void)
#define NUM_XFERS
Definition: usb_libusb10.h:57
int freenect_stop_audio(freenect_device *dev)
Definition: audio.c:198
#define PKTS_PER_XFER
Definition: usb_libusb10.h:56
static freenect_context * ctx
static void prepare_iso_out_data(freenect_device *dev, uint8_t *buffer)
Definition: audio.c:34
int freenect_start_audio(freenect_device *dev)
Definition: audio.c:149
uint16_t last_seen_window[10]
fnusb_isoc_stream audio_out_isoc
freenect_audio_out_cb audio_out_cb
int16_t * cancelled_buffer
freenect_audio_in_cb audio_in_cb
int32_t * mic_buffer[4]


libfreenect
Author(s): Hector Martin, Josh Blake, Kyle Machulis, OpenKinect community
autogenerated on Mon Jun 10 2019 13:46:42