Codebase list squeezelite / 5064c9f
0.5beta1 checkin Support for AAC in MP4 file playback (makes several simplifying assumptions) Remove glibc specific eventfd calls so compiles with ulibc Add support for big endian processors Add ablity to fix volume to 100% via LMS setting Hide some more warnings when libraries not present Adrian Smith 11 years ago
9 changed file(s) with 289 addition(s) and 75 deletion(s). Raw diff Collapse all Expand all
+144
-40
faad.c less more
2828
2929 struct faad {
3030 NeAACDecHandle hAac;
31 u8_t type;
3132 // faad symbols to be dynamically loaded
3233 unsigned long (* NeAACDecGetCapabilities)(void);
3334 NeAACDecConfigurationPtr (* NeAACDecGetCurrentConfiguration)(NeAACDecHandle);
3536 NeAACDecHandle (* NeAACDecOpen)(void);
3637 void (* NeAACDecClose)(NeAACDecHandle);
3738 long (* NeAACDecInit)(NeAACDecHandle, unsigned char *, unsigned long, unsigned long *, unsigned char *);
39 char (* NeAACDecInit2)(NeAACDecHandle, unsigned char *pBuffer, unsigned long, unsigned long *, unsigned char *);
3840 void *(* NeAACDecDecode)(NeAACDecHandle, NeAACDecFrameInfo *, unsigned char *, unsigned long);
3941 char *(* NeAACDecGetErrorMessage)(unsigned char);
4042 };
5658
5759 typedef u_int32_t frames_t;
5860
61 // minimal code for mp4 file parsing to extract audio config and find media data
62
63 // adapted from faad2/common/mp4ff
64 u32_t mp4_desc_length(u8_t **buf) {
65 u8_t b;
66 u8_t num_bytes = 0;
67 u32_t length = 0;
68
69 do {
70 b = **buf;
71 *buf += 1;
72 num_bytes++;
73 length = (length << 7) | (b & 0x7f);
74 } while ((b & 0x80) && num_bytes < 4);
75
76 return length;
77 }
78
79 // read mp4 header to extract config data - assume this occurs at start of streambuf
80 static int read_mp4_header(unsigned long *samplerate_p, unsigned char *channels_p) {
81 size_t bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
82 char type[5];
83 u32_t len;
84
85 while (bytes >= 8) {
86 len = unpackN((u32_t *)streambuf->readp);
87 memcpy(type, streambuf->readp + 4, 4);
88 type[4] = '\0';
89
90 // extract audio config from within esds and pass to DecInit2
91 if (!strcmp(type, "esds") && bytes > len) {
92 u8_t *ptr = streambuf->readp + 12;
93 if (*ptr++ == 0x03) {
94 mp4_desc_length(&ptr);
95 ptr += 4;
96 } else {
97 ptr += 3;
98 }
99 mp4_desc_length(&ptr);
100 ptr += 13;
101 if (*ptr++ != 0x05) {
102 LOG_WARN("error parsing esds");
103 return -1;
104 }
105 unsigned config_len = mp4_desc_length(&ptr);
106 if (a->NeAACDecInit2(a->hAac, ptr, config_len, samplerate_p, channels_p) != 0) {
107 LOG_WARN("bad audio config");
108 return -1;
109 }
110 }
111
112 // found media data, advance past header and return
113 // currently assume audio samples are packed with no gaps into mdat from this point - we don't use stsz, stsc to find them
114 if (!strcmp(type, "mdat")) {
115 LOG_DEBUG("type: mdat");
116 _buf_inc_readp(streambuf, 8);
117 if (len == 1) {
118 _buf_inc_readp(streambuf, 8);
119 }
120 return 1;
121 }
122
123 // default to consuming entire box
124 u32_t consume = len;
125
126 // read into these boxes so reduce consume
127 if (!strcmp(type, "moov") || !strcmp(type, "trak") || !strcmp(type, "mdia") || !strcmp(type, "minf") || !strcmp(type, "stbl")) {
128 consume = 8;
129 }
130 if (!strcmp(type, "stsd")) consume = 16;
131 if (!strcmp(type, "mp4a")) consume = 36;
132
133 if (bytes > len) {
134 LOG_DEBUG("type: %s len: %u consume: %u", type, len, consume);
135 _buf_inc_readp(streambuf, consume);
136 bytes -= consume;
137 } else if (len > streambuf->size / 2) {
138 LOG_WARN("type: %s len: %u - excessive length can't parse", type, len);
139 return -1;
140 } else {
141 break;
142 }
143 }
144
145 return 0;
146 }
147
59148 static void faad_decode(void) {
60149 LOCK_S;
61150 size_t bytes_total = _buf_used(streambuf);
62151 size_t bytes_wrap = min(bytes_total, _buf_cont_read(streambuf));
63152
64153 if (decode.new_stream) {
65
66 // find adts sync at start of header
67 while (bytes_wrap >= 2 && (*(streambuf->readp) != 0xFF || (*(streambuf->readp + 1) & 0xF6) != 0xF0)) {
68 _buf_inc_readp(streambuf, 1);
69 bytes_total--;
70 bytes_wrap--;
71 }
72
73 unsigned char channels;
74 unsigned long samplerate;
75
76 long n = a->NeAACDecInit(a->hAac, streambuf->readp, bytes_wrap, &samplerate, &channels);
77 if (n < 0) {
78 LOG_WARN("error initialising - ending stream");
154 int found = 0;
155 static unsigned char channels;
156 static unsigned long samplerate;
157
158 if (a->type == '2') {
159
160 LOG_INFO("opening atds stream");
161
162 while (bytes_wrap >= 2 && (*(streambuf->readp) != 0xFF || (*(streambuf->readp + 1) & 0xF6) != 0xF0)) {
163 _buf_inc_readp(streambuf, 1);
164 bytes_total--;
165 bytes_wrap--;
166 }
167
168 long n = a->NeAACDecInit(a->hAac, streambuf->readp, bytes_wrap, &samplerate, &channels);
169 if (n < 0) {
170 found = -1;
171 } else {
172 _buf_inc_readp(streambuf, n);
173 found = 1;
174 }
175
176 } else {
177
178 LOG_INFO("opening mp4 stream");
179
180 found = read_mp4_header(&samplerate, &channels);
181 }
182
183 if (found == 1) {
184
185 LOG_INFO("samplerate: %u channels: %u", samplerate, channels);
186 bytes_total = _buf_used(streambuf);
187 bytes_wrap = min(bytes_total, _buf_cont_read(streambuf));
188
189 LOCK_O;
190 LOG_INFO("setting track_start");
191 output.next_sample_rate = samplerate;
192 output.track_start = outputbuf->writep;
193 decode.new_stream = false;
194 UNLOCK_O;
195 }
196
197 if (found == -1) {
198
199 LOG_WARN("error reading stream header");
79200 UNLOCK_S;
80201 LOCK_O;
81202 decode.state = DECODE_ERROR;
82203 UNLOCK_O;
83204 return;
84205 }
85
86 _buf_inc_readp(streambuf, n);
87 bytes_total = _buf_used(streambuf);
88 bytes_wrap = min(bytes_total, _buf_cont_read(streambuf));
89
90 LOG_INFO("setting track_start");
91 output.next_sample_rate = samplerate;
92 output.track_start = outputbuf->writep;
93 decode.new_stream = false;
94206 }
95207
96208 NeAACDecFrameInfo info;
97
98209 s32_t *iptr;
99210
100211 if (bytes_wrap < WRAPBUF_LEN && bytes_total > WRAPBUF_LEN) {
135246
136247 if (info.channels == 2) {
137248 while (count--) {
138 *optr++ = *iptr++;
139 *optr++ = *iptr++;
249 *optr++ = *iptr++ << 8;
250 *optr++ = *iptr++ << 8;
140251 }
141252 } else if (info.channels == 1) {
142253 while (count--) {
143 *optr++ = *iptr;
144 *optr++ = *iptr++;
254 *optr++ = *iptr << 8;
255 *optr++ = *iptr++ << 8;
145256 }
146257 } else {
147258 LOG_WARN("unsupported number of channels");
153264
154265 UNLOCK_O;
155266
156 LOG_SDEBUG("wrote %u frames", info.samples);
267 LOG_SDEBUG("wrote %u frames", info.samples / info.channels);
157268 }
158269
159270 static void faad_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
160 if (size == '2') {
161 LOG_INFO("opening adts stream");
162 } else {
163 LOG_ERROR("aac stream type %c not supported", size);
164 LOCK_O;
165 decode.state = DECODE_ERROR;
166 UNLOCK_O;
167 return;
168 }
271 a->type = size;
169272
170273 if (a->hAac) {
171274 a->NeAACDecClose(a->hAac);
174277
175278 NeAACDecConfigurationPtr conf = a->NeAACDecGetCurrentConfiguration(a->hAac);
176279
177 conf->outputFormat = FAAD_FMT_32BIT;
280 conf->outputFormat = FAAD_FMT_24BIT;
178281 conf->downMatrix = 1;
179282
180283 if (!a->NeAACDecSetConfiguration(a->hAac, conf)) {
190293 static bool load_faad() {
191294 void *handle = dlopen(LIBFAAD, RTLD_NOW);
192295 if (!handle) {
193 LOG_WARN("dlerror: %s", dlerror());
296 LOG_INFO("dlerror: %s", dlerror());
194297 return false;
195298 }
196299
203306 a->NeAACDecOpen = dlsym(handle, "NeAACDecOpen");
204307 a->NeAACDecClose = dlsym(handle, "NeAACDecClose");
205308 a->NeAACDecInit = dlsym(handle, "NeAACDecInit");
309 a->NeAACDecInit2 = dlsym(handle, "NeAACDecInit2");
206310 a->NeAACDecDecode = dlsym(handle, "NeAACDecDecode");
207311 a->NeAACDecGetErrorMessage = dlsym(handle, "NeAACDecGetErrorMessage");
208312
157157 static bool load_flac() {
158158 void *handle = dlopen(LIBFLAC, RTLD_NOW);
159159 if (!handle) {
160 LOG_WARN("dlerror: %s", dlerror());
160 LOG_INFO("dlerror: %s", dlerror());
161161 return false;
162162 }
163163
170170 static bool load_mad() {
171171 void *handle = dlopen(LIBMAD, RTLD_NOW);
172172 if (!handle) {
173 LOG_WARN("dlerror: %s", dlerror());
173 LOG_INFO("dlerror: %s", dlerror());
174174 return false;
175175 }
176176
2727
2828 #define MAX_SILENCE_FRAMES 1024
2929
30 // for mmap ouput we convert to LE formats on BE devices as it is likely hardware requires LE
3031 static snd_pcm_format_t fmts_mmap[] = { SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S24_LE, SND_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_S16_LE,
3132 SND_PCM_FORMAT_UNKNOWN };
3233
33 static snd_pcm_format_t fmts_writei[] = { SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_UNKNOWN };
34 // for non mmap output we rely on ALSA to do the conversion and just open the device in native 32bit native endian
35 static snd_pcm_format_t fmts_writei[] = {
36 #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
37 SND_PCM_FORMAT_S32_LE,
38 #else
39 SND_PCM_FORMAT_S32_BE,
40 #endif
41 SND_PCM_FORMAT_UNKNOWN };
3442
3543 typedef unsigned frames_t;
3644
4452 } alsa;
4553
4654 struct outputstate output;
47
48 #define FIXED_ONE 0x10000
4955
5056 static inline s32_t gain(s32_t gain, s32_t sample) {
5157 s64_t res = (s64_t)gain * (s64_t)sample;
484490 switch(alsa.format) {
485491 case SND_PCM_FORMAT_S16_LE:
486492 {
493 #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
487494 s16_t *optr = (s16_t *)(void *)outputptr;
488495 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
489496 while (cnt--) {
496503 *(optr++) = gain(gainR, *(inputptr++)) >> 16;
497504 }
498505 }
506 #else
507 u8_t *optr = (u8_t *)(void *)outputptr;
508 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
509 while (cnt--) {
510 *(optr++) = (*(inputptr) & 0x00ff0000) >> 16;
511 *(optr++) = (*(inputptr++) & 0xff000000) >> 24;
512 *(optr++) = (*(inputptr) & 0x00ff0000) >> 16;
513 *(optr++) = (*(inputptr++) & 0xff000000) >> 24;
514 }
515 } else {
516 while (cnt--) {
517 s32_t lsample = gain(gainL, *(inputptr++));
518 s32_t rsample = gain(gainR, *(inputptr++));
519 *(optr++) = (lsample & 0x00ff0000) >> 16;
520 *(optr++) = (lsample & 0xff000000) >> 24;
521 *(optr++) = (rsample & 0x00ff0000) >> 16;
522 *(optr++) = (rsample & 0xff000000) >> 24;
523 }
524 }
525 #endif
499526 }
500527 break;
501528 case SND_PCM_FORMAT_S24_LE:
502529 {
530 #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
503531 s32_t *optr = (s32_t *)(void *)outputptr;
504532 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
505533 while (cnt--) {
512540 *(optr++) = gain(gainR, *(inputptr++)) >> 8;
513541 }
514542 }
543 #else
544 u8_t *optr = (u8_t *)(void *)outputptr;
545 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
546 while (cnt--) {
547 *(optr++) = (*(inputptr) & 0x0000ff00) >> 8;
548 *(optr++) = (*(inputptr) & 0x00ff0000) >> 16;
549 *(optr++) = (*(inputptr++) & 0xff000000) >> 24;
550 *(optr++) = 0;
551 *(optr++) = (*(inputptr) & 0x0000ff00) >> 8;
552 *(optr++) = (*(inputptr) & 0x00ff0000) >> 16;
553 *(optr++) = (*(inputptr++) & 0xff000000) >> 24;
554 *(optr++) = 0;
555 }
556 } else {
557 while (cnt--) {
558 s32_t lsample = gain(gainL, *(inputptr++));
559 s32_t rsample = gain(gainR, *(inputptr++));
560 *(optr++) = (lsample & 0x0000ff00) >> 8;
561 *(optr++) = (lsample & 0x00ff0000) >> 16;
562 *(optr++) = (lsample & 0xff000000) >> 24;
563 *(optr++) = 0;
564 *(optr++) = (rsample & 0x0000ff00) >> 8;
565 *(optr++) = (rsample & 0x00ff0000) >> 16;
566 *(optr++) = (rsample & 0xff000000) >> 24;
567 *(optr++) = 0;
568 }
569 }
570 #endif
515571 }
516572 break;
517573 case SND_PCM_FORMAT_S24_3LE:
526582 while (cnt >= 2) {
527583 s32_t l1 = *(inputptr++); s32_t r1 = *(inputptr++);
528584 s32_t l2 = *(inputptr++); s32_t r2 = *(inputptr++);
585 #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
529586 *(o_ptr++) = (l1 & 0xffffff00) >> 8 | (r1 & 0x0000ff00) << 16;
530587 *(o_ptr++) = (r1 & 0xffff0000) >> 16 | (l2 & 0x00ffff00) << 8;
531588 *(o_ptr++) = (l2 & 0xff000000) >> 24 | (r2 & 0xffffff00);
589 #else
590 *(o_ptr++) = (l1 & 0x0000ff00) << 16 | (l1 & 0x00ff0000) | (l1 & 0xff000000) >> 16 |
591 (r1 & 0x0000ff00) >> 8;
592 *(o_ptr++) = (r1 & 0x00ff0000) << 8 | (r1 & 0xff000000) >> 8 | (l2 & 0x0000ff00) |
593 (l2 & 0x00ff0000) >> 16;
594 *(o_ptr++) = (l2 & 0xff000000) | (r2 & 0x0000ff00) << 8 | (r2 & 0x00ff0000) >> 8 |
595 (r2 & 0xff000000) >> 24;
596 #endif
532597 optr += 12;
533598 cnt -= 2;
534599 }
553618 while (cnt >= 2) {
554619 s32_t l1 = gain(gainL, *(inputptr++)); s32_t r1 = gain(gainR, *(inputptr++));
555620 s32_t l2 = gain(gainL, *(inputptr++)); s32_t r2 = gain(gainR, *(inputptr++));
621 #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
556622 *(o_ptr++) = (l1 & 0xffffff00) >> 8 | (r1 & 0x0000ff00) << 16;
557623 *(o_ptr++) = (r1 & 0xffff0000) >> 16 | (l2 & 0x00ffff00) << 8;
558624 *(o_ptr++) = (l2 & 0xff000000) >> 24 | (r2 & 0xffffff00);
625 #else
626 *(o_ptr++) = (l1 & 0x0000ff00) << 16 | (l1 & 0x00ff0000) | (l1 & 0xff000000) >> 16 |
627 (r1 & 0x0000ff00) >> 8;
628 *(o_ptr++) = (r1 & 0x00ff0000) << 8 | (r1 & 0xff000000) >> 8 | (l2 & 0x0000ff00) |
629 (l2 & 0x00ff0000) >> 16;
630 *(o_ptr++) = (l2 & 0xff000000) | (r2 & 0x0000ff00) << 8 | (r2 & 0x00ff0000) >> 8 |
631 (r2 & 0xff000000) >> 24;
632 #endif
559633 optr += 12;
560634 cnt -= 2;
561635 }
576650 break;
577651 case SND_PCM_FORMAT_S32_LE:
578652 {
653 #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
579654 s32_t *optr = (s32_t *)(void *)outputptr;
580655 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
581656 memcpy(outputptr, inputptr, cnt * BYTES_PER_FRAME);
585660 *(optr++) = gain(gainR, *(inputptr++));
586661 }
587662 }
663 #else
664 u8_t *optr = (u8_t *)(void *)outputptr;
665 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
666 while (cnt--) {
667 *(optr++) = (*(inputptr) & 0x000000ff);
668 *(optr++) = (*(inputptr) & 0x0000ff00) >> 8;
669 *(optr++) = (*(inputptr) & 0x00ff0000) >> 16;
670 *(optr++) = (*(inputptr++) & 0xff000000) >> 24;
671 *(optr++) = (*(inputptr) & 0x000000ff);
672 *(optr++) = (*(inputptr) & 0x0000ff00) >> 8;
673 *(optr++) = (*(inputptr) & 0x00ff0000) >> 16;
674 *(optr++) = (*(inputptr++) & 0xff000000) >> 24;
675 }
676 } else {
677 while (cnt--) {
678 s32_t lsample = gain(gainL, *(inputptr++));
679 s32_t rsample = gain(gainR, *(inputptr++));
680 *(optr++) = (lsample & 0x000000ff);
681 *(optr++) = (lsample & 0x0000ff00) >> 8;
682 *(optr++) = (lsample & 0x00ff0000) >> 16;
683 *(optr++) = (lsample & 0xff000000) >> 24;
684 *(optr++) = (rsample & 0x000000ff);
685 *(optr++) = (rsample & 0x0000ff00) >> 8;
686 *(optr++) = (rsample & 0x00ff0000) >> 16;
687 *(optr++) = (rsample & 0xff000000) >> 24;
688 }
689 }
690 #endif
588691 }
589692 break;
590693 default:
7777 }
7878 }
7979
80 inline void packN(u32_t *dest, u32_t val) {
81 u8_t *ptr = (u8_t *)dest;
82 *(ptr) = (val >> 24) & 0xFF; *(ptr+1) = (val >> 16) & 0xFF; *(ptr+2) = (val >> 8) & 0xFF; *(ptr+3) = val & 0xFF;
83 }
84
85 inline void packn(u16_t *dest, u16_t val) {
86 u8_t *ptr = (u8_t *)dest;
87 *(ptr) = (val >> 8) & 0xFF; *(ptr+1) = val & 0xFF;
88 }
89
90 inline u32_t unpackN(u32_t *src) {
91 u8_t *ptr = (u8_t *)src;
92 return *(ptr) << 24 | *(ptr+1) << 16 | *(ptr+2) << 8 | *(ptr+3);
93 }
94
95 inline u16_t unpackn(u16_t *src) {
96 u8_t *ptr = (u8_t *)src;
97 return *(ptr) << 8 | *(ptr+1);
98 }
99
10080 static void sendHELO(bool reconnect, const char *cap, u8_t mac[6]) {
101 const char *capbase = "Model=squeezelite,ModelName=SqueezeLite,AccuratePlayPoints=1,";
81 const char *capbase = "Model=squeezelite,ModelName=SqueezeLite,AccuratePlayPoints=1,HasDigitalOut=1,";
10282
10383 struct HELO_packet pkt = {
10484 .opcode = "HELO",
310290 audg->gainL = unpackN(&audg->gainL);
311291 audg->gainR = unpackN(&audg->gainR);
312292
313 LOG_INFO("audg gainL: %u gainR: %u", audg->gainL, audg->gainR);
293 LOG_INFO("audg gainL: %u gainR: %u adjust: %u", audg->gainL, audg->gainR, audg->adjust);
314294
315295 LOCK_O;
316 output.gainL = audg->gainL;
317 output.gainR = audg->gainR;
296 output.gainL = audg->adjust ? audg->gainL : FIXED_ONE;
297 output.gainR = audg->adjust ? audg->gainR : FIXED_ONE;
318298 UNLOCK_O;
319299 }
320300
393373 }
394374
395375 if (pollinfo[1].revents) {
396 eventfd_t val;
397 eventfd_read(efd, &val);
376 uint64_t u;
377 u = read(efd, &u, sizeof(uint64_t));
398378 wake = true;
399379 }
400380 }
501481
502482 // called from other threads to wake state machine above
503483 void wake_controller(void) {
504 eventfd_write(efd, 1);
484 uint64_t u = 1;
485 u = write(efd, &u, sizeof(uint64_t));
505486 }
506487
507488 in_addr_t discover_server(void) {
113113 char opcode[4];
114114 u32_t old_gainL; // unused
115115 u32_t old_gainR; // unused
116 u8_t fixed_digital; // unused
116 u8_t adjust;
117117 u8_t preamp; // unused
118118 u32_t gainL;
119119 u32_t gainR;
3434 #include <sys/types.h>
3535 #include <poll.h>
3636
37 #define VERSION "v0.4beta2"
37 #define VERSION "v0.5beta1"
3838
3939 #define STREAMBUF_SIZE (2 * 1024 * 1024)
4040 #define OUTPUTBUF_SIZE (44100 * 8 * 10)
4747
4848 #define ALSA_BUFFER_TIME 20000
4949 #define ALSA_PERIOD_COUNT 4
50
51 #define FIXED_ONE 0x10000
5052
5153 typedef u_int8_t u8_t;
5254 typedef u_int16_t u16_t;
7577 // utils.c (non logging)
7678 u32_t gettime_ms(void);
7779 void get_mac(u8_t *mac);
80 inline void packN(u32_t *dest, u32_t val);
81 inline void packn(u16_t *dest, u16_t val);
82 inline u32_t unpackN(u32_t *src);
83 inline u16_t unpackn(u16_t *src);
7884
7985 // buffer.c
8086 struct buffer {
8383 close(s);
8484 }
8585
86 // pack/unpack to network byte order
87 inline void packN(u32_t *dest, u32_t val) {
88 u8_t *ptr = (u8_t *)dest;
89 *(ptr) = (val >> 24) & 0xFF; *(ptr+1) = (val >> 16) & 0xFF; *(ptr+2) = (val >> 8) & 0xFF; *(ptr+3) = val & 0xFF;
90 }
91
92 inline void packn(u16_t *dest, u16_t val) {
93 u8_t *ptr = (u8_t *)dest;
94 *(ptr) = (val >> 8) & 0xFF; *(ptr+1) = val & 0xFF;
95 }
96
97 inline u32_t unpackN(u32_t *src) {
98 u8_t *ptr = (u8_t *)src;
99 return *(ptr) << 24 | *(ptr+1) << 16 | *(ptr+2) << 8 | *(ptr+3);
100 }
101
102 inline u16_t unpackn(u16_t *src) {
103 u8_t *ptr = (u8_t *)src;
104 return *(ptr) << 8 | *(ptr+1);
105 }
183183 if (handle) {
184184 tremor = true;
185185 } else {
186 LOG_WARN("dlerror: %s", dlerror());
186 LOG_INFO("dlerror: %s", dlerror());
187187 return false;
188188 }
189189 }