1 /*
2 	Audio File Library
3 	Copyright (C) 2011-2013, Michael Pruett <michael@68k.org>
4 
5 	This library is free software; you can redistribute it and/or
6 	modify it under the terms of the GNU Lesser General Public
7 	License as published by the Free Software Foundation; either
8 	version 2.1 of the License, or (at your option) any later version.
9 
10 	This library is distributed in the hope that it will be useful,
11 	but WITHOUT ANY WARRANTY; without even the implied warranty of
12 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 	Lesser General Public License for more details.
14 
15 	You should have received a copy of the GNU Lesser General Public
16 	License along with this library; if not, write to the
17 	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 	Boston, MA  02110-1301  USA
19 */
20 
21 #include "config.h"
22 #include "CAF.h"
23 
24 #include "Buffer.h"
25 #include "File.h"
26 #include "PacketTable.h"
27 #include "Setup.h"
28 #include "Tag.h"
29 #include "Track.h"
30 #include "byteorder.h"
31 #include "util.h"
32 
33 #include <stdint.h>
34 #include <string.h>
35 #include <string>
36 #include <vector>
37 
38 const int _af_caf_compression_types[_AF_CAF_NUM_COMPTYPES] =
39 {
40 	AF_COMPRESSION_G711_ULAW,
41 	AF_COMPRESSION_G711_ALAW,
42 	AF_COMPRESSION_IMA,
43 	AF_COMPRESSION_ALAC
44 };
45 
46 enum
47 {
48 	kCAFLinearPCMFormatFlagIsFloat = (1L << 0),
49 	kCAFLinearPCMFormatFlagIsLittleEndian = (1L << 1)
50 };
51 
52 enum
53 {
54 	kALACFormatFlag_16BitSourceData = 1,
55 	kALACFormatFlag_20BitSourceData = 2,
56 	kALACFormatFlag_24BitSourceData = 3,
57 	kALACFormatFlag_32BitSourceData = 4
58 };
59 
60 static const unsigned kALACDefaultFramesPerPacket = 4096;
61 
62 static const _AFfilesetup cafDefaultFileSetup =
63 {
64 	_AF_VALID_FILESETUP,	// valid
65 	AF_FILE_CAF,			// fileFormat
66 	true,					// trackSet
67 	true,					// instrumentSet
68 	true,					// miscellaneousSet
69 	1,						// trackCount
70 	NULL,					// tracks
71 	1,						// instrumentCount
72 	NULL,					// instruments
73 	0,						// miscellaneousCount
74 	NULL					// miscellaneous
75 };
76 
CAFFile()77 CAFFile::CAFFile() :
78 	m_dataOffset(-1),
79 	m_cookieDataOffset(-1)
80 {
81 	setFormatByteOrder(AF_BYTEORDER_BIGENDIAN);
82 }
83 
~CAFFile()84 CAFFile::~CAFFile()
85 {
86 }
87 
recognize(File * file)88 bool CAFFile::recognize(File *file)
89 {
90 	file->seek(0, File::SeekFromBeginning);
91 	uint8_t buffer[8];
92 	if (file->read(buffer, 8) != 8 || memcmp(buffer, "caff", 4) != 0)
93 		return false;
94 	const uint8_t versionAndFlags[4] = { 0, 1, 0, 0 };
95 	if (memcmp(buffer + 4, versionAndFlags, 4) != 0)
96 		return false;
97 	return true;
98 }
99 
readInit(AFfilesetup setup)100 status CAFFile::readInit(AFfilesetup setup)
101 {
102 	m_fh->seek(8, File::SeekFromBeginning);
103 
104 	if (!allocateTrack())
105 		return AF_FAIL;
106 
107 	off_t currentOffset = m_fh->tell();
108 	off_t fileLength = m_fh->length();
109 
110 	while (currentOffset < fileLength)
111 	{
112 		Tag chunkType;
113 		int64_t chunkLength;
114 		if (!readTag(&chunkType) ||
115 			!readS64(&chunkLength))
116 			return AF_FAIL;
117 
118 		currentOffset += 12;
119 
120 		if (chunkType == "data" && chunkLength == -1)
121 			chunkLength = fileLength - currentOffset;
122 		else if (chunkLength < 0)
123 			_af_error(AF_BAD_HEADER,
124 				"invalid chunk length %jd for chunk type %s\n",
125 				static_cast<intmax_t>(chunkLength), chunkType.name().c_str());
126 
127 		if (chunkType == "desc")
128 		{
129 			if (parseDescription(chunkType, chunkLength) == AF_FAIL)
130 				return AF_FAIL;
131 		}
132 		else if (chunkType == "data")
133 		{
134 			if (parseData(chunkType, chunkLength) == AF_FAIL)
135 				return AF_FAIL;
136 		}
137 		else if (chunkType == "pakt")
138 		{
139 			if (parsePacketTable(chunkType, chunkLength) == AF_FAIL)
140 				return AF_FAIL;
141 		}
142 		else if (chunkType == "kuki")
143 		{
144 			if (parseCookieData(chunkType, chunkLength) == AF_FAIL)
145 				return AF_FAIL;
146 		}
147 
148 		currentOffset = m_fh->seek(currentOffset + chunkLength,
149 			File::SeekFromBeginning);
150 	}
151 
152 	return AF_SUCCEED;
153 }
154 
writeInit(AFfilesetup setup)155 status CAFFile::writeInit(AFfilesetup setup)
156 {
157 	if (initFromSetup(setup) == AF_FAIL)
158 		return AF_FAIL;
159 
160 	initCompressionParams();
161 
162 	Tag caff("caff");
163 	if (!writeTag(&caff)) return AF_FAIL;
164 	const uint8_t versionAndFlags[4] = { 0, 1, 0, 0 };
165 	if (m_fh->write(versionAndFlags, 4) != 4) return AF_FAIL;
166 
167 	if (writeDescription() == AF_FAIL)
168 		return AF_FAIL;
169 	if (writeCookieData() == AF_FAIL)
170 		return AF_FAIL;
171 	if (writeData(false) == AF_FAIL)
172 		return AF_FAIL;
173 
174 	return AF_SUCCEED;
175 }
176 
completeSetup(AFfilesetup setup)177 AFfilesetup CAFFile::completeSetup(AFfilesetup setup)
178 {
179 	if (setup->trackSet && setup->trackCount != 1)
180 	{
181 		_af_error(AF_BAD_NUMTRACKS, "CAF file must have 1 track");
182 		return AF_NULL_FILESETUP;
183 	}
184 
185 	TrackSetup *track = &setup->tracks[0];
186 
187 	if (track->sampleFormatSet)
188 	{
189 		if (track->f.isUnsigned())
190 		{
191 			_af_error(AF_BAD_FILEFMT, "CAF format does not support unsigned data");
192 			return AF_NULL_FILESETUP;
193 		}
194 	}
195 	else
196 		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP,
197 			track->f.sampleWidth);
198 
199 	if (track->f.isSigned() && (track->f.sampleWidth < 1 || track->f.sampleWidth > 32))
200 	{
201 		_af_error(AF_BAD_WIDTH,
202 			"invalid sample width %d for CAF file (must be 1-32)",
203 			track->f.sampleWidth);
204 		return AF_NULL_FILESETUP;
205 	}
206 
207 	if (!track->byteOrderSet)
208 		track->f.byteOrder = _AF_BYTEORDER_NATIVE;
209 
210 	if (track->f.compressionType != AF_COMPRESSION_NONE &&
211 		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
212 		track->f.compressionType != AF_COMPRESSION_G711_ALAW &&
213 		track->f.compressionType != AF_COMPRESSION_IMA &&
214 		track->f.compressionType != AF_COMPRESSION_ALAC)
215 	{
216 		_af_error(AF_BAD_COMPTYPE,
217 			"compression format %d not supported in CAF file",
218 			track->f.compressionType);
219 		return AF_NULL_FILESETUP;
220 	}
221 
222 	if (track->markersSet && track->markerCount)
223 	{
224 		_af_error(AF_BAD_NOT_IMPLEMENTED, "CAF does not yet support markers");
225 		return AF_NULL_FILESETUP;
226 	}
227 
228 	if (track->aesDataSet)
229 	{
230 		_af_error(AF_BAD_FILESETUP, "CAF does not support AES data");
231 		return AF_NULL_FILESETUP;
232 	}
233 
234 	return _af_filesetup_copy(setup, &cafDefaultFileSetup, true);
235 }
236 
update()237 status CAFFile::update()
238 {
239 	if (writeCookieData() == AF_FAIL)
240 		return AF_FAIL;
241 	if (writeData(true) == AF_FAIL)
242 		return AF_FAIL;
243 	if (writePacketTable() == AF_FAIL)
244 		return AF_FAIL;
245 	return AF_SUCCEED;
246 }
247 
parseDescription(const Tag &,int64_t)248 status CAFFile::parseDescription(const Tag &, int64_t)
249 {
250 	double sampleRate;
251 	Tag formatID;
252 	uint32_t formatFlags;
253 	uint32_t bytesPerPacket;
254 	uint32_t framesPerPacket;
255 	uint32_t channelsPerFrame;
256 	uint32_t bitsPerChannel;
257 	if (!readDouble(&sampleRate) ||
258 		!readTag(&formatID) ||
259 		!readU32(&formatFlags) ||
260 		!readU32(&bytesPerPacket) ||
261 		!readU32(&framesPerPacket) ||
262 		!readU32(&channelsPerFrame) ||
263 		!readU32(&bitsPerChannel))
264 		return AF_FAIL;
265 
266 	if (!channelsPerFrame)
267 	{
268 		_af_error(AF_BAD_CHANNELS, "invalid file with 0 channels");
269 		return AF_FAIL;
270 	}
271 
272 	Track *track = getTrack();
273 	track->f.channelCount = channelsPerFrame;
274 	track->f.sampleWidth = bitsPerChannel;
275 	track->f.sampleRate = sampleRate;
276 	track->f.framesPerPacket = 1;
277 
278 	if (formatID == "lpcm")
279 	{
280 		track->f.compressionType = AF_COMPRESSION_NONE;
281 		if (formatFlags & kCAFLinearPCMFormatFlagIsFloat)
282 		{
283 			if (bitsPerChannel != 32 && bitsPerChannel != 64)
284 			{
285 				_af_error(AF_BAD_WIDTH, "invalid bits per sample %d for floating-point audio data", bitsPerChannel);
286 				return AF_FAIL;
287 			}
288 			track->f.sampleFormat = bitsPerChannel == 32 ? AF_SAMPFMT_FLOAT :
289 				AF_SAMPFMT_DOUBLE;
290 		}
291 		else
292 		{
293 			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
294 		}
295 		track->f.byteOrder = (formatFlags & kCAFLinearPCMFormatFlagIsLittleEndian) ?
296 			AF_BYTEORDER_LITTLEENDIAN : AF_BYTEORDER_BIGENDIAN;
297 
298 		if (_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth) == AF_FAIL)
299 			return AF_FAIL;
300 
301 		track->f.computeBytesPerPacketPCM();
302 		return AF_SUCCEED;
303 	}
304 	else if (formatID == "ulaw")
305 	{
306 		track->f.compressionType = AF_COMPRESSION_G711_ULAW;
307 		track->f.byteOrder = _AF_BYTEORDER_NATIVE;
308 		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
309 		track->f.bytesPerPacket = channelsPerFrame;
310 		return AF_SUCCEED;
311 	}
312 	else if (formatID == "alaw")
313 	{
314 		track->f.compressionType = AF_COMPRESSION_G711_ALAW;
315 		track->f.byteOrder = _AF_BYTEORDER_NATIVE;
316 		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
317 		track->f.bytesPerPacket = channelsPerFrame;
318 		return AF_SUCCEED;
319 	}
320 	else if (formatID == "ima4")
321 	{
322 		track->f.compressionType = AF_COMPRESSION_IMA;
323 		track->f.byteOrder = _AF_BYTEORDER_NATIVE;
324 		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
325 		initIMACompressionParams();
326 		return AF_SUCCEED;
327 	}
328 	else if (formatID == "alac")
329 	{
330 		track->f.compressionType = AF_COMPRESSION_ALAC;
331 		track->f.byteOrder = _AF_BYTEORDER_NATIVE;
332 		switch (formatFlags)
333 		{
334 			case kALACFormatFlag_16BitSourceData:
335 				track->f.sampleWidth = 16; break;
336 			case kALACFormatFlag_20BitSourceData:
337 				track->f.sampleWidth = 20; break;
338 			case kALACFormatFlag_24BitSourceData:
339 				track->f.sampleWidth = 24; break;
340 			case kALACFormatFlag_32BitSourceData:
341 				track->f.sampleWidth = 32; break;
342 			default:
343 				_af_error(AF_BAD_CODEC_TYPE,
344 					"unsupported format flags for ALAC: %u", formatFlags);
345 				return AF_FAIL;
346 		}
347 		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP,
348 			track->f.sampleWidth);
349 		track->f.framesPerPacket = framesPerPacket;
350 		track->f.bytesPerPacket = 0;
351 		return AF_SUCCEED;
352 	}
353 	else
354 	{
355 		_af_error(AF_BAD_NOT_IMPLEMENTED, "Compression type %s not supported",
356 			formatID.name().c_str());
357 		return AF_FAIL;
358 	}
359 }
360 
parseData(const Tag & tag,int64_t length)361 status CAFFile::parseData(const Tag &tag, int64_t length)
362 {
363 	uint32_t editCount;
364 	if (!readU32(&editCount))
365 		return AF_FAIL;
366 
367 	Track *track = getTrack();
368 	if (length == -1)
369 		track->data_size = m_fh->length() - m_fh->tell();
370 	else
371 		track->data_size = length - 4;
372 	track->fpos_first_frame = m_fh->tell();
373 
374 	track->computeTotalFileFrames();
375 	return AF_SUCCEED;
376 }
377 
readBERInteger(const uint8_t * input,size_t * numBytes)378 static uint32_t readBERInteger(const uint8_t *input, size_t *numBytes)
379 {
380 	uint32_t result = 0;
381 	uint8_t data;
382 	size_t size = 0;
383 	do
384 	{
385 		data = input[size];
386 		result = (result << 7) | (data & 0x7f);
387 		if (++size > 5)
388 			return 0;
389 	} while ((data & 0x80) && size < *numBytes);
390 	*numBytes = size;
391 	return result;
392 }
393 
encodeBERInteger(uint32_t value,uint8_t * buffer,size_t * numBytes)394 static void encodeBERInteger(uint32_t value, uint8_t *buffer, size_t *numBytes)
395 {
396 	if ((value & 0x7f) == value)
397 	{
398 		*numBytes = 1;
399 		buffer[0] = value;
400 	}
401 	else if ((value & 0x3fff) == value)
402 	{
403 		*numBytes = 2;
404 		buffer[0] = (value >> 7) | 0x80;
405 		buffer[1] = value & 0x7f;
406 	}
407 	else if ((value & 0x1fffff) == value)
408 	{
409 		*numBytes = 3;
410 		buffer[0] = (value >> 14) | 0x80;
411 		buffer[1] = ((value >> 7) & 0x7f) | 0x80;
412 		buffer[2] = value & 0x7f;
413 	}
414 	else if ((value & 0x0fffffff) == value)
415 	{
416 		*numBytes = 4;
417 		buffer[0] = (value >> 21) | 0x80;
418 		buffer[1] = ((value >> 14) & 0x7f) | 0x80;
419 		buffer[2] = ((value >> 7) & 0x7f) | 0x80;
420 		buffer[3] = value & 0x7f;
421 	}
422 	else
423 	{
424 		*numBytes = 5;
425 		buffer[0] = (value >> 28) | 0x80;
426 		buffer[1] = ((value >> 21) & 0x7f) | 0x80;
427 		buffer[2] = ((value >> 14) & 0x7f) | 0x80;
428 		buffer[3] = ((value >> 7) & 0x7f) | 0x80;
429 		buffer[4] = value & 0x7f;
430 	}
431 }
432 
parsePacketTable(const Tag & tag,int64_t length)433 status CAFFile::parsePacketTable(const Tag &tag, int64_t length)
434 {
435 	if (length < 24)
436 		return AF_FAIL;
437 
438 	int64_t numPackets;
439 	int64_t numValidFrames;
440 	int32_t primingFrames;
441 	int32_t remainderFrames;
442 	if (!readS64(&numPackets) ||
443 		!readS64(&numValidFrames) ||
444 		!readS32(&primingFrames) ||
445 		!readS32(&remainderFrames))
446 	{
447 		return AF_FAIL;
448 	}
449 
450 	if (!numPackets)
451 		return AF_SUCCEED;
452 
453 	int64_t tableLength = length - 24;
454 
455 	SharedPtr<Buffer> buffer = new Buffer(tableLength);
456 	if (m_fh->read(buffer->data(), tableLength) != tableLength)
457 		return AF_FAIL;
458 
459 	SharedPtr<PacketTable> packetTable = new PacketTable(numValidFrames,
460 		primingFrames, remainderFrames);
461 
462 	const uint8_t *data = static_cast<const uint8_t *>(buffer->data());
463 	size_t position = 0;
464 	while (position < buffer->size())
465 	{
466 		size_t sizeRemaining = buffer->size() - position;
467 		uint32_t bytesPerPacket = readBERInteger(data + position, &sizeRemaining);
468 		if (bytesPerPacket == 0)
469 			break;
470 		packetTable->append(bytesPerPacket);
471 		position += sizeRemaining;
472 	}
473 
474 	assert(numPackets == packetTable->numPackets());
475 
476 	Track *track = getTrack();
477 	track->m_packetTable = packetTable;
478 	track->totalfframes = numValidFrames;
479 
480 	return AF_SUCCEED;
481 }
482 
parseCookieData(const Tag & tag,int64_t length)483 status CAFFile::parseCookieData(const Tag &tag, int64_t length)
484 {
485 	m_codecData = new Buffer(length);
486 	if (m_fh->read(m_codecData->data(), length) != length)
487 		return AF_FAIL;
488 
489 	AUpvlist pv = AUpvnew(2);
490 
491 	AUpvsetparam(pv, 0, _AF_CODEC_DATA_SIZE);
492 	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
493 	long l = length;
494 	AUpvsetval(pv, 0, &l);
495 
496 	AUpvsetparam(pv, 1, _AF_CODEC_DATA);
497 	AUpvsetvaltype(pv, 1, AU_PVTYPE_PTR);
498 	void *v = m_codecData->data();
499 	AUpvsetval(pv, 1, &v);
500 
501 	Track *track = getTrack();
502 	track->f.compressionParams = pv;
503 
504 	return AF_SUCCEED;
505 }
506 
writeDescription()507 status CAFFile::writeDescription()
508 {
509 	Track *track = getTrack();
510 
511 	Tag desc("desc");
512 	int64_t chunkLength = 32;
513 	double sampleRate = track->f.sampleRate;
514 	Tag formatID("lpcm");
515 	uint32_t formatFlags = 0;
516 	if (track->f.byteOrder == AF_BYTEORDER_LITTLEENDIAN)
517 		formatFlags |= kCAFLinearPCMFormatFlagIsLittleEndian;
518 	if (track->f.isFloat())
519 		formatFlags |= kCAFLinearPCMFormatFlagIsFloat;
520 	uint32_t bytesPerPacket = track->f.bytesPerFrame(false);
521 	uint32_t framesPerPacket = 1;
522 	uint32_t channelsPerFrame = track->f.channelCount;
523 	uint32_t bitsPerChannel = track->f.sampleWidth;
524 
525 	if (track->f.compressionType == AF_COMPRESSION_G711_ULAW)
526 	{
527 		formatID = "ulaw";
528 		formatFlags = 0;
529 		bytesPerPacket = channelsPerFrame;
530 		bitsPerChannel = 8;
531 	}
532 	else if (track->f.compressionType == AF_COMPRESSION_G711_ALAW)
533 	{
534 		formatID = "alaw";
535 		formatFlags = 0;
536 		bytesPerPacket = channelsPerFrame;
537 		bitsPerChannel = 8;
538 	}
539 	else if (track->f.compressionType == AF_COMPRESSION_IMA)
540 	{
541 		formatID = "ima4";
542 		formatFlags = 0;
543 		bytesPerPacket = track->f.bytesPerPacket;
544 		framesPerPacket = track->f.framesPerPacket;
545 		bitsPerChannel = 16;
546 	}
547 	else if (track->f.compressionType == AF_COMPRESSION_ALAC)
548 	{
549 		formatID = "alac";
550 		switch (track->f.sampleWidth)
551 		{
552 			case 16: formatFlags = kALACFormatFlag_16BitSourceData; break;
553 			case 20: formatFlags = kALACFormatFlag_20BitSourceData; break;
554 			case 24: formatFlags = kALACFormatFlag_24BitSourceData; break;
555 			case 32: formatFlags = kALACFormatFlag_32BitSourceData; break;
556 		}
557 		bytesPerPacket = track->f.bytesPerPacket;
558 		framesPerPacket = track->f.framesPerPacket;
559 	}
560 
561 	if (!writeTag(&desc) ||
562 		!writeS64(&chunkLength) ||
563 		!writeDouble(&sampleRate) ||
564 		!writeTag(&formatID) ||
565 		!writeU32(&formatFlags) ||
566 		!writeU32(&bytesPerPacket) ||
567 		!writeU32(&framesPerPacket) ||
568 		!writeU32(&channelsPerFrame) ||
569 		!writeU32(&bitsPerChannel))
570 		return AF_FAIL;
571 	return AF_SUCCEED;
572 }
573 
writeData(bool update)574 status CAFFile::writeData(bool update)
575 {
576 	Track *track = getTrack();
577 
578 	if (m_dataOffset == -1)
579 		m_dataOffset = m_fh->tell();
580 	else
581 		m_fh->seek(m_dataOffset, File::SeekFromBeginning);
582 
583 	Tag data("data");
584 	int64_t dataLength = -1;
585 	uint32_t editCount = 0;
586 	if (update)
587 		dataLength = track->data_size + 4;
588 
589 	if (!writeTag(&data) ||
590 		!writeS64(&dataLength) ||
591 		!writeU32(&editCount))
592 		return AF_FAIL;
593 	if (track->fpos_first_frame == 0)
594 		track->fpos_first_frame = m_fh->tell();
595 	return AF_SUCCEED;
596 }
597 
writePacketTable()598 status CAFFile::writePacketTable()
599 {
600 	Track *track = getTrack();
601 
602 	m_fh->seek(track->fpos_after_data, File::SeekFromBeginning);
603 
604 	SharedPtr<PacketTable> packetTable = track->m_packetTable;
605 	if (!packetTable)
606 		return AF_SUCCEED;
607 
608 	int64_t numPackets = packetTable->numPackets();
609 	int64_t numValidFrames = packetTable->numValidFrames();
610 	int32_t primingFrames = packetTable->primingFrames();
611 	int32_t remainderFrames = packetTable->remainderFrames();
612 
613 	SharedPtr<Buffer> buffer = new Buffer(packetTable->numPackets() * 5);
614 
615 	uint8_t *data = static_cast<uint8_t *>(buffer->data());
616 	size_t position = 0;
617 	for (unsigned i=0; i<packetTable->numPackets(); i++)
618 	{
619 		uint32_t bytesPerPacket = packetTable->bytesPerPacket(i);
620 		size_t numBytes = 0;
621 		encodeBERInteger(bytesPerPacket, data + position, &numBytes);
622 		position += numBytes;
623 	}
624 
625 	Tag pakt("pakt");
626 	int64_t packetTableLength = 24 + position;
627 
628 	if (!writeTag(&pakt) ||
629 		!writeS64(&packetTableLength) ||
630 		!writeS64(&numPackets) ||
631 		!writeS64(&numValidFrames) ||
632 		!writeS32(&primingFrames) ||
633 		!writeS32(&remainderFrames) ||
634 		m_fh->write(buffer->data(), position) != static_cast<ssize_t>(position))
635 	{
636 		return AF_FAIL;
637 	}
638 
639 	return AF_SUCCEED;
640 }
641 
writeCookieData()642 status CAFFile::writeCookieData()
643 {
644 	if (!m_codecData)
645 		return AF_SUCCEED;
646 
647 	if (m_cookieDataOffset == -1)
648 		m_cookieDataOffset = m_fh->tell();
649 	else
650 		m_fh->seek(m_cookieDataOffset, File::SeekFromBeginning);
651 
652 	Tag kuki("kuki");
653 	int64_t cookieDataLength = m_codecData->size();
654 	if (!writeTag(&kuki) ||
655 		!writeS64(&cookieDataLength) ||
656 		m_fh->write(m_codecData->data(), m_codecData->size()) != static_cast<ssize_t>(m_codecData->size()))
657 	{
658 		return AF_FAIL;
659 	}
660 
661 	return AF_SUCCEED;
662 }
663 
initCompressionParams()664 void CAFFile::initCompressionParams()
665 {
666 	Track *track = getTrack();
667 	if (track->f.compressionType == AF_COMPRESSION_IMA)
668 		initIMACompressionParams();
669 	else if (track->f.compressionType == AF_COMPRESSION_ALAC)
670 		initALACCompressionParams();
671 }
672 
initIMACompressionParams()673 void CAFFile::initIMACompressionParams()
674 {
675 	Track *track = getTrack();
676 
677 	track->f.bytesPerPacket = 34 * track->f.channelCount;
678 	track->f.framesPerPacket = 64;
679 
680 	AUpvlist pv = AUpvnew(1);
681 	AUpvsetparam(pv, 0, _AF_IMA_ADPCM_TYPE);
682 	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
683 	long l = _AF_IMA_ADPCM_TYPE_QT;
684 	AUpvsetval(pv, 0, &l);
685 
686 	track->f.compressionParams = pv;
687 }
688 
initALACCompressionParams()689 void CAFFile::initALACCompressionParams()
690 {
691 	if (m_access == _AF_READ_ACCESS)
692 		return;
693 
694 	Track *track = getTrack();
695 
696 	track->f.bytesPerPacket = 0;
697 	track->f.framesPerPacket = kALACDefaultFramesPerPacket;
698 
699 	const unsigned kALACSpecificConfigSize = 24;
700 	const unsigned kChannelAtomSize = 12;
701 	const unsigned kALACAudioChannelLayoutSize = 12;
702 
703 	unsigned codecDataSize = kALACSpecificConfigSize;
704 	if (track->f.channelCount > 2)
705 		codecDataSize += kChannelAtomSize + kALACAudioChannelLayoutSize;
706 	m_codecData = new Buffer(codecDataSize);
707 	bzero(m_codecData->data(), m_codecData->size());
708 
709 	AUpvlist pv = AUpvnew(2);
710 
711 	AUpvsetparam(pv, 0, _AF_CODEC_DATA_SIZE);
712 	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
713 	long l = codecDataSize;
714 	AUpvsetval(pv, 0, &l);
715 
716 	AUpvsetparam(pv, 1, _AF_CODEC_DATA);
717 	AUpvsetvaltype(pv, 1, AU_PVTYPE_PTR);
718 	void *v = m_codecData->data();
719 	AUpvsetval(pv, 1, &v);
720 
721 	track->f.compressionParams = pv;
722 
723 	track->m_packetTable = new PacketTable();
724 }
725