xref: /haiku/src/add-ons/kernel/drivers/audio/usb/Stream.cpp (revision a5a3b2d9a3d95cbae71eaf371708c73a1780ac0d)
1 /*
2  *	Driver for USB Audio Device Class devices.
3  *	Copyright (c) 2009-13 S.Zharski <imker@gmx.li>
4  *	Distributed under the terms of the MIT license.
5  *
6  */
7 
8 
9 #include "Stream.h"
10 
11 #include <usb/USB_audio.h>
12 
13 #include "Device.h"
14 #include "Driver.h"
15 #include "Settings.h"
16 
17 
18 Stream::Stream(Device* device, size_t interface, usb_interface_list* List)
19 	:
20 	AudioStreamingInterface(&device->AudioControl(), interface, List),
21 	fDevice(device),
22 	fStatus(B_NO_INIT),
23 	fStreamEndpoint(0),
24 	fIsRunning(false),
25 	fArea(-1),
26 	fAreaSize(0),
27 	fDescriptors(NULL),
28 	fDescriptorsCount(0),
29 	fCurrentBuffer(0),
30 	fStartingFrame(0),
31 	fSamplesCount(0),
32 	fPacketSize(0),
33 	fProcessedBuffers(0),
34 	fInsideNotify(0)
35 {
36 }
37 
38 
39 Stream::~Stream()
40 {
41 	delete_area(fArea);
42 }
43 
44 
45 status_t
46 Stream::_ChooseAlternate()
47 {
48 	// lookup alternate with maximal (ch * 100 + resolution)
49 	uint16 maxChxRes = 0;
50 	for (int i = 0; i < fAlternates.Count(); i++) {
51 		if (fAlternates[i]->Interface() == 0) {
52 			TRACE(INF, "Ignore alternate %d - zero interface description.\n", i);
53 			continue;
54 		}
55 
56 		if (fAlternates[i]->Format() == 0) {
57 			TRACE(INF, "Ignore alternate %d - zero format description.\n", i);
58 			continue;
59 		}
60 
61 		if (fAlternates[i]->Format()->fFormatType
62 				!= USB_AUDIO_FORMAT_TYPE_I) {
63 			TRACE(ERR, "Ignore alternate %d - format type %#02x "
64 				"is not supported.\n", i, fAlternates[i]->Format()->fFormatType);
65 			continue;
66 		}
67 
68 		switch (fAlternates[i]->Interface()->fFormatTag) {
69 			case USB_AUDIO_FORMAT_PCM:
70 			case USB_AUDIO_FORMAT_PCM8:
71 			case USB_AUDIO_FORMAT_IEEE_FLOAT:
72 		//	case USB_AUDIO_FORMAT_ALAW:
73 		//	case USB_AUDIO_FORMAT_MULAW:
74 				break;
75 			default:
76 				TRACE(ERR, "Ignore alternate %d - format %#04x is not "
77 					"supported.\n", i, fAlternates[i]->Interface()->fFormatTag);
78 			continue;
79 		}
80 
81 		TypeIFormatDescriptor* format
82 			= static_cast<TypeIFormatDescriptor*>(fAlternates[i]->Format());
83 
84 		if (format->fNumChannels > 2) {
85 			TRACE(ERR, "Ignore alternate %d - channel count %d "
86 				"is not supported.\n", i, format->fNumChannels);
87 			continue;
88 		}
89 
90 		if (fAlternates[i]->Interface()->fFormatTag == USB_AUDIO_FORMAT_PCM) {
91 			switch(format->fBitResolution) {
92 				default:
93 				TRACE(ERR, "Ignore alternate %d - bit resolution %d "
94 					"is not supported.\n", i, format->fBitResolution);
95 					continue;
96 				case 8: case 16: case 18: case 20: case 24: case 32:
97 					break;
98 			}
99 		}
100 
101 		uint16 chxRes = format->fNumChannels * 100 + format->fBitResolution;
102 		if (chxRes > maxChxRes) {
103 			maxChxRes = chxRes;
104 			fActiveAlternate = i;
105 		}
106 	}
107 
108 	if (maxChxRes <= 0) {
109 		TRACE(ERR, "No compatible alternate found. "
110 			"Stream initialization failed.\n");
111 		return B_NO_INIT;
112 	}
113 
114 	const ASEndpointDescriptor* endpoint
115 		= fAlternates[fActiveAlternate]->Endpoint();
116 	fIsInput = (endpoint->fEndpointAddress & USB_ENDPOINT_ADDR_DIR_IN)
117 		== USB_ENDPOINT_ADDR_DIR_IN;
118 
119 	if (fIsInput)
120 		fCurrentBuffer = (size_t)-1;
121 
122 	TRACE(INF, "Alternate %d EP:%x selected for %s!\n",
123 		fActiveAlternate, endpoint->fEndpointAddress,
124 		fIsInput ? "recording" : "playback");
125 
126 	return B_OK;
127 }
128 
129 
130 status_t
131 Stream::Init()
132 {
133 	fStatus = _ChooseAlternate();
134 	return fStatus;
135 }
136 
137 
138 void
139 Stream::OnRemove()
140 {
141 	// the transfer callback schedule traffic - so we must ensure that we are
142 	// not inside the callback anymore before returning, as we would otherwise
143 	// violate the promise not to use any of the pipes after returning from the
144 	// removed callback
145 	while (atomic_add(&fInsideNotify, 0) != 0)
146 		snooze(100);
147 
148 	gUSBModule->cancel_queued_transfers(fStreamEndpoint);
149 }
150 
151 
152 status_t
153 Stream::_SetupBuffers()
154 {
155 	// allocate buffer for worst (maximal size) case
156 	TypeIFormatDescriptor* format = static_cast<TypeIFormatDescriptor*>(
157 		fAlternates[fActiveAlternate]->Format());
158 
159 	uint32 samplingRate = fAlternates[fActiveAlternate]->GetSamplingRate();
160 	uint32 sampleSize = format->fNumChannels * format->fSubframeSize;
161 
162 	// data size pro 1 ms USB 1 frame or 1/8 ms USB 2 microframe
163 	fPacketSize = samplingRate * sampleSize
164 		/ (fDevice->fUSBVersion < 0x0200 ? 1000 : 8000);
165 	TRACE(INF, "packetSize:%ld\n", fPacketSize);
166 
167 	if (fArea == -1) {
168 		fAreaSize = (sizeof(usb_iso_packet_descriptor) + fPacketSize)
169 			* sampleSize * 1024 / fPacketSize;
170 		TRACE(INF, "estimate fAreaSize:%d\n", fAreaSize);
171 
172 		// round up to B_PAGE_SIZE and create area
173 		fAreaSize = (fAreaSize + (B_PAGE_SIZE - 1)) &~ (B_PAGE_SIZE - 1);
174 		TRACE(INF, "rounded up fAreaSize:%d\n", fAreaSize);
175 
176 		fArea = create_area( (fIsInput) ? DRIVER_NAME "_record_area"
177 			: DRIVER_NAME "_playback_area", (void**)&fDescriptors,
178 			B_ANY_KERNEL_ADDRESS, fAreaSize, B_CONTIGUOUS,
179 			B_READ_AREA | B_WRITE_AREA);
180 
181 		if (fArea < 0) {
182 			TRACE(ERR, "Error of creating %#x - "
183 				"bytes size buffer area:%#010x\n", fAreaSize, fArea);
184 			fStatus = fArea;
185 			return fStatus;
186 		}
187 
188 		TRACE(INF, "Created area id:%d at addr:%#010x size:%#010lx\n",
189 			fArea, fDescriptors, fAreaSize);
190 	}
191 
192 	// descriptors count
193 	fDescriptorsCount = fAreaSize
194 		/ (sizeof(usb_iso_packet_descriptor) + fPacketSize);
195 
196 	// we need same size sub-buffers. round it
197 	fDescriptorsCount /= kSamplesBufferCount;
198 	fDescriptorsCount *= kSamplesBufferCount;
199 	TRACE(INF, "descriptorsCount:%d\n", fDescriptorsCount);
200 
201 	// samples count
202 	fSamplesCount = fDescriptorsCount * fPacketSize / sampleSize;
203 	TRACE(INF, "samplesCount:%d\n", fSamplesCount);
204 
205 	// initialize descriptors array
206 	for (size_t i = 0; i < fDescriptorsCount; i++) {
207 		fDescriptors[i].request_length = fPacketSize;
208 		fDescriptors[i].actual_length = 0;
209 		fDescriptors[i].status = B_OK;
210 	}
211 
212 	return fStatus;
213 }
214 
215 
216 status_t
217 Stream::OnSetConfiguration(usb_device device,
218 		const usb_configuration_info* config)
219 {
220 	if (config == NULL) {
221 		TRACE(ERR, "NULL configuration. Not set.\n");
222 		return B_ERROR;
223 	}
224 
225 	usb_interface_info* interface
226 		= &config->interface[fInterface].alt[fActiveAlternate];
227 	if (interface == NULL) {
228 		TRACE(ERR, "NULL interface. Not set.\n");
229 		return B_ERROR;
230 	}
231 
232 	status_t status = gUSBModule->set_alt_interface(device, interface);
233 	uint8 address = fAlternates[fActiveAlternate]->Endpoint()->fEndpointAddress;
234 
235 	TRACE(INF, "set_alt_interface %x\n", status);
236 
237 	for (size_t i = 0; i < interface->endpoint_count; i++) {
238 		if (address == interface->endpoint[i].descr->endpoint_address) {
239 			fStreamEndpoint = interface->endpoint[i].handle;
240 			TRACE(INF, "%s Stream Endpoint [address %#04x] handle is: %#010x.\n",
241 				fIsInput ? "Input" : "Output", address, fStreamEndpoint);
242 			return B_OK;
243 		}
244 	}
245 
246 	TRACE(INF, "%s Stream Endpoint [address %#04x] was not found.\n",
247 		fIsInput ? "Input" : "Output", address);
248 	return B_ERROR;
249 }
250 
251 
252 status_t
253 Stream::Start()
254 {
255 	status_t result = B_BUSY;
256 	if (!fIsRunning) {
257 		for (size_t i = 0; i < kSamplesBufferCount; i++)
258 			result = _QueueNextTransfer(i, true);
259 		fIsRunning = result == B_OK;
260 	}
261 	return result;
262 }
263 
264 
265 status_t
266 Stream::Stop()
267 {
268 	if (fIsRunning) {
269 		// wait until possible notification handling finished...
270 		while (atomic_add(&fInsideNotify, 0) != 0)
271 			snooze(100);
272 		gUSBModule->cancel_queued_transfers(fStreamEndpoint);
273 		fIsRunning = false;
274 	}
275 
276 	return B_OK;
277 }
278 
279 
280 status_t
281 Stream::_QueueNextTransfer(size_t queuedBuffer, bool start)
282 {
283 	TypeIFormatDescriptor* format = static_cast<TypeIFormatDescriptor*>(
284 		fAlternates[fActiveAlternate]->Format());
285 
286 	size_t bufferSize = format->fNumChannels * format->fSubframeSize;
287 	bufferSize *= fSamplesCount / kSamplesBufferCount;
288 
289 	uint8* buffers = (uint8*)(fDescriptors + fDescriptorsCount);
290 
291 	size_t packetsCount = fDescriptorsCount / kSamplesBufferCount;
292 
293 	TRACE(DTA, "buffers:%#010x[%#x]\ndescrs:%#010x[%#x]\n",
294 		buffers + bufferSize * queuedBuffer, bufferSize,
295 		fDescriptors + queuedBuffer * packetsCount, packetsCount);
296 
297 	status_t status = gUSBModule->queue_isochronous(fStreamEndpoint,
298 		buffers + bufferSize * queuedBuffer, bufferSize,
299 		fDescriptors + queuedBuffer * packetsCount, packetsCount,
300 		&fStartingFrame, start ? USB_ISO_ASAP : 0,
301 		Stream::_TransferCallback, this);
302 
303 	TRACE(DTA, "frame:%#010x\n", fStartingFrame);
304 	return status; // B_OK;
305 }
306 
307 
308 void
309 Stream::_TransferCallback(void* cookie, status_t status, void* data,
310 	size_t actualLength)
311 {
312 	Stream* stream = (Stream*)cookie;
313 	atomic_add(&stream->fInsideNotify, 1);
314 	if (status == B_CANCELED || stream->fDevice->fRemoved) {
315 		atomic_add(&stream->fInsideNotify, -1);
316 		TRACE(ERR, "Cancelled: c:%p st:%#010x, data:%#010x, len:%d\n",
317 			cookie, status, data, actualLength);
318 		return;
319 	}
320 
321 	stream->fCurrentBuffer = (stream->fCurrentBuffer + 1) % kSamplesBufferCount;
322 
323 	stream->_DumpDescriptors();
324 
325 	/*status_t result =*/ stream->_QueueNextTransfer(stream->fCurrentBuffer, false);
326 
327 	if (atomic_add(&stream->fProcessedBuffers, 1) > (int32)kSamplesBufferCount)
328 		TRACE(ERR, "Processed buffers overflow:%d\n", stream->fProcessedBuffers);
329 
330 	release_sem_etc(stream->fDevice->fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE);
331 
332 	TRACE(DTA, "st:%#010x, data:%#010x, len:%d\n", status, data, actualLength);
333 
334 	atomic_add(&stream->fInsideNotify, -1);
335 }
336 
337 
338 void
339 Stream::_DumpDescriptors()
340 {
341 	//size_t packetsCount = fDescriptorsCount / kSamplesBufferCount;
342 	size_t from = /*fCurrentBuffer > 0 ? packetsCount :*/ 0 ;
343 	size_t to   = /*fCurrentBuffer > 0 ?*/ fDescriptorsCount /*: packetsCount*/ ;
344 	for (size_t i = from; i < to; i++)
345 		TRACE(ISO, "%d:req_len:%d; act_len:%d; stat:%#010x\n", i,
346 			fDescriptors[i].request_length,	fDescriptors[i].actual_length,
347 			fDescriptors[i].status);
348 }
349 
350 
351 status_t
352 Stream::GetEnabledChannels(uint32& offset, multi_channel_enable* Enable)
353 {
354 	AudioChannelCluster* cluster = ChannelCluster();
355 	if (cluster == 0)
356 		return B_ERROR;
357 
358 	for (size_t i = 0; i < cluster->ChannelsCount(); i++) {
359 		B_SET_CHANNEL(Enable->enable_bits, offset++, true);
360 		TRACE(INF, "Report channel %d as enabled.\n", offset);
361 	}
362 
363 	return B_OK;
364 }
365 
366 
367 status_t
368 Stream::SetEnabledChannels(uint32& offset, multi_channel_enable* Enable)
369 {
370 	AudioChannelCluster* cluster = ChannelCluster();
371 	if (cluster == 0)
372 		return B_ERROR;
373 
374 	for (size_t i = 0; i < cluster->ChannelsCount(); i++, offset++) {
375 		TRACE(INF, "%s channel %d.\n",
376 			(B_TEST_CHANNEL(Enable->enable_bits, offset)
377 			? "Enable" : "Disable"), offset + 1);
378 	}
379 
380 	return B_OK;
381 }
382 
383 
384 status_t
385 Stream::GetGlobalFormat(multi_format_info* Format)
386 {
387 	_multi_format* format = fIsInput ? &Format->input : &Format->output;
388 	format->cvsr = fAlternates[fActiveAlternate]->GetSamplingRate();
389 	format->rate = fAlternates[fActiveAlternate]->GetSamplingRateId(0);
390 	format->format = fAlternates[fActiveAlternate]->GetFormatId();
391 	TRACE(INF, "%s.rate:%d cvsr:%f format:%#08x\n",
392 		fIsInput ? "input" : "ouput",
393 		format->rate, format->cvsr, format->format);
394 	return B_OK;
395 }
396 
397 
398 status_t
399 Stream::SetGlobalFormat(multi_format_info* Format)
400 {
401 	_multi_format* format = fIsInput ? &Format->input : &Format->output;
402 	AudioStreamAlternate* alternate = fAlternates[fActiveAlternate];
403 	if (format->rate == alternate->GetSamplingRateId(0)
404 			&& format->format == alternate->GetFormatId()) {
405 		TRACE(INF, "No changes required\n");
406 		return B_OK;
407 	}
408 
409 	alternate->SetSamplingRateById(format->rate);
410 	alternate->SetFormatId(format->format);
411 	TRACE(INF, "%s.rate:%d cvsr:%f format:%#08x\n",
412 		fIsInput ? "input" : "ouput",
413 		format->rate, format->cvsr, format->format);
414 
415 	// cancel data flow - it will be rewaked at next buffer exchange call
416 	Stop();
417 
418 	// TODO: wait for cancelling?
419 
420 	// layout of buffers should be adjusted after changing sampling rate/format
421 	status_t status = _SetupBuffers();
422 
423 	if (status != B_OK)
424 		return status;
425 
426 	// set endpoint speed
427 	uint32 samplingRate = fAlternates[fActiveAlternate]->GetSamplingRate();
428 	size_t actualLength = 0;
429 	usb_audio_sampling_freq freq = _ASFormatDescriptor::GetSamFreq(samplingRate);
430 	uint8 address = fAlternates[fActiveAlternate]->Endpoint()->fEndpointAddress;
431 
432 	status = gUSBModule->send_request(fDevice->fDevice,
433 		USB_REQTYPE_CLASS | USB_REQTYPE_ENDPOINT_OUT,
434 		USB_AUDIO_SET_CUR, USB_AUDIO_SAMPLING_FREQ_CONTROL << 8,
435 		address, sizeof(freq), &freq, &actualLength);
436 
437 	TRACE(ERR, "set_speed %02x%02x%02x for ep %#x %d: %x\n",
438 		freq.bytes[0], freq.bytes[1], freq.bytes[2],
439 		address, actualLength, status);
440 	return status;
441 }
442 
443 
444 status_t
445 Stream::GetBuffers(multi_buffer_list* List)
446 {
447 // TODO: check the available buffers count!
448 	if (fAreaSize == 0)
449 		return B_NO_INIT;
450 
451 	int32 startChannel = List->return_playback_channels;
452 	buffer_desc** Buffers = List->playback_buffers;
453 
454 	if (fIsInput) {
455 		List->flags |= B_MULTI_BUFFER_RECORD;
456 		List->return_record_buffer_size = fSamplesCount / kSamplesBufferCount;
457 		List->return_record_buffers = kSamplesBufferCount;
458 		startChannel = List->return_record_channels;
459 		Buffers = List->record_buffers;
460 
461 		TRACE(DTA, "flags:%#10x\nreturn_record_buffer_size:%#010x\n"
462 			"return_record_buffers:%#010x\n", List->flags,
463 			List->return_record_buffer_size, List->return_record_buffers);
464 	} else {
465 		List->flags |= B_MULTI_BUFFER_PLAYBACK;
466 		List->return_playback_buffer_size = fSamplesCount / kSamplesBufferCount;
467 		List->return_playback_buffers = kSamplesBufferCount;
468 
469 		TRACE(DTA, "flags:%#10x\nreturn_playback_buffer_size:%#010x\n"
470 			"return_playback_buffers:%#010x\n", List->flags,
471 			List->return_playback_buffer_size, List->return_playback_buffers);
472 	}
473 
474 	TypeIFormatDescriptor* format = static_cast<TypeIFormatDescriptor*>(
475 		fAlternates[fActiveAlternate]->Format());
476 //	const ASEndpointDescriptor* endpoint
477 //					= fAlternates[fActiveAlternate]->Endpoint();
478 
479 	// [buffer][channel] init buffers
480 	for (size_t buffer = 0; buffer < kSamplesBufferCount; buffer++) {
481 		TRACE(DTA, "%s buffer #%d:\n", fIsInput ? "input" : "output", buffer + 1);
482 
483 		for (size_t channel = startChannel;
484 				channel < format->fNumChannels; channel++) {
485 			// init stride to the same for all buffers
486 			uint32 stride = format->fSubframeSize * format->fNumChannels;
487 			Buffers[buffer][channel].stride = stride;
488 
489 			// init to buffers area begin
490 			Buffers[buffer][channel].base
491 				= (char*)(fDescriptors + fDescriptorsCount);
492 			// shift for whole buffer if required
493 			size_t bufferSize = fPacketSize/*endpoint->fMaxPacketSize*/
494 				* (fDescriptorsCount / kSamplesBufferCount);
495 			Buffers[buffer][channel].base += buffer * bufferSize;
496 			// shift for channel if required
497 			Buffers[buffer][channel].base += channel * format->fSubframeSize;
498 
499 			TRACE(DTA, "%d:%d: base:%#010x; stride:%#010x\n", buffer, channel,
500 				Buffers[buffer][channel].base, Buffers[buffer][channel].stride);
501 		}
502 	}
503 
504 	if (fIsInput) {
505 		List->return_record_channels += format->fNumChannels;
506 		TRACE(MIX, "return_record_channels:%#010x\n",
507 			List->return_record_channels);
508 	} else {
509 		List->return_playback_channels += format->fNumChannels;
510 		TRACE(MIX, "return_playback_channels:%#010x\n",
511 			List->return_playback_channels);
512 	}
513 
514 	return B_OK;
515 }
516 
517 
518 bool
519 Stream::ExchangeBuffer(multi_buffer_info* Info)
520 {
521 	if (fProcessedBuffers <= 0)
522 		return false;
523 
524 	if (fIsInput) {
525 		Info->recorded_real_time = system_time();// TODO fRealTime;
526 		Info->recorded_frames_count += fSamplesCount / kSamplesBufferCount;
527 		Info->record_buffer_cycle = fCurrentBuffer;
528 	} else {
529 		Info->played_real_time = system_time();// TODO fRealTime;
530 		Info->played_frames_count += fSamplesCount / kSamplesBufferCount;
531 		Info->playback_buffer_cycle = fCurrentBuffer;
532 	}
533 
534 	atomic_add(&fProcessedBuffers, -1);
535 
536 	return true;
537 }
538 
539