Codebase list squeezelite / f56b8a1
add visexport capablity for linux Adrian Smith 10 years ago
4 changed file(s) with 168 addition(s) and 7 deletion(s). Raw diff Collapse all Expand all
00 # Make with portaudio rather than direct alsa
1 OPTS = -DPORTAUDIO
1 OPTS += -DPORTAUDIO
22 LDFLAGS = -lportaudio -lpthread -ldl -lrt
33 EXECUTABLE = squeezelite-pa
44
6464 " \t\t\t stopband_start = number in percent (Aliasing/imaging control. > passband_end),\n"
6565 " \t\t\t phase_response = 0-100 (0 = minimum / 50 = linear / 100 = maximum)\n"
6666 #endif
67 #if VISEXPORT
68 " -v \t\t\tVisulizer support\n"
69 #endif
6770 #if LINUX
6871 " -z \t\t\tDaemonize\n"
6972 #endif
99102 #endif
100103 #if FFMPEG
101104 " FFMPEG"
105 #endif
106 #if VISEXPORT
107 " VISEXPORT"
102108 #endif
103109 "\n\n",
104110 argv0);
151157 unsigned pa_latency = 0;
152158 int pa_osx_playnice = -1;
153159 #endif
160 #if VISEXPORT
161 bool visexport = false;
162 #endif
154163
155164 log_level log_output = lWARN;
156165 log_level log_stream = lWARN;
167176 if (strstr("oabcdfmnprs", opt) && optind < argc - 1) {
168177 optarg = argv[optind + 1];
169178 optind += 2;
170 #if RESAMPLE
171 } else if (strstr("ltuz", opt)) {
172 #else
173 } else if (strstr("ltz", opt)) {
174 #endif
179 } else if (strstr("ltz"
180 #if RESAMPLE
181 "u"
182 #endif
183 #if VISEXPORT
184 "v"
185 #endif
186 , opt)) {
175187 optarg = NULL;
176188 optind += 1;
177189 } else {
278290 }
279291 break;
280292 #endif
293 #if VISEXPORT
294 case 'v':
295 visexport = true;
296 break;
297 #endif
281298 #if LINUX
282299 case 'z':
283300 daemonize = true;
336353 output_init(log_output, output_device, output_buf_size, pa_latency, pa_osx_playnice, max_rate);
337354 #endif
338355
356 #if VISEXPORT
357 if (visexport) {
358 output_vis_init(mac);
359 }
360 #endif
361
339362 decode_init(log_decode, codecs);
340363
341364 #if RESAMPLE
3333 #include <pa_mac_core.h>
3434 #endif
3535 #endif
36 #if VISEXPORT && !ALSA
37 #include <sys/mman.h>
38 #include <fcntl.h>
39 #endif
3640
3741 #if ALSA
3842
7377 } pa;
7478
7579 #endif // PORTAUDIO
80
81 #if VISEXPORT
82
83 #define VIS_BUF_SIZE 16384
84 #define VIS_LOCK_NS 1000000 // ns to wait for vis wrlock
85
86 static struct vis_t {
87 pthread_rwlock_t rwlock;
88 u32_t buf_size;
89 u32_t buf_index;
90 bool running;
91 u32_t rate;
92 time_t updated;
93 s16_t buffer[VIS_BUF_SIZE];
94 } *vis_mmap = NULL;
95
96 static char vis_shm_path[40];
97 static int vis_fd = -1;
98
99 #endif // VISEXPORT
76100
77101 static log_level loglevel;
78102
734758 pcmp = NULL;
735759 output_off = true;
736760 LOG_INFO("disabling output");
761 #if VISEXPORT
762 if (vis_mmap) {
763 pthread_rwlock_wrlock(&vis_mmap->rwlock);
764 vis_mmap->running = false;
765 pthread_rwlock_unlock(&vis_mmap->rwlock);
766 }
767 #endif
737768 continue;
738769 }
739770
12851316 }
12861317
12871318 size -= out_frames;
1319
1320 #if VISEXPORT
1321 // attempt to write audio to vis_mmap but do not wait more than VIS_LOCK_NS to get wrlock
1322 // this can result in missing audio export to the mmap region, but this is preferable dropping audio
1323 if (vis_mmap) {
1324 int err;
1325 err = pthread_rwlock_trywrlock(&vis_mmap->rwlock);
1326 if (err) {
1327 struct timespec ts;
1328 clock_gettime(CLOCK_REALTIME, &ts);
1329 ts.tv_nsec += VIS_LOCK_NS;
1330 if (ts.tv_nsec > 1000000000) {
1331 ts.tv_sec += 1;
1332 ts.tv_nsec -= 1000000000;
1333 }
1334 err = pthread_rwlock_timedwrlock(&vis_mmap->rwlock, &ts);
1335 }
1336
1337 if (err) {
1338 LOG_DEBUG("failed to get wrlock - skipping visulizer export");
1339
1340 } else {
1341
1342 if (silence) {
1343 vis_mmap->running = false;
1344 } else {
1345 frames_t vis_cnt = out_frames;
1346 s32_t *ptr = (s32_t *) outputbuf->readp;
1347 unsigned i = vis_mmap->buf_index;
1348
1349 if (!output.current_replay_gain) {
1350 while (vis_cnt--) {
1351 vis_mmap->buffer[i++] = *(ptr++) >> 16;
1352 vis_mmap->buffer[i++] = *(ptr++) >> 16;
1353 if (i == VIS_BUF_SIZE) i = 0;
1354 }
1355 } else {
1356 while (vis_cnt--) {
1357 vis_mmap->buffer[i++] = gain(*(ptr++), output.current_replay_gain) >> 16;
1358 vis_mmap->buffer[i++] = gain(*(ptr++), output.current_replay_gain) >> 16;
1359 if (i == VIS_BUF_SIZE) i = 0;
1360 }
1361 }
1362
1363 vis_mmap->updated = time(NULL);
1364 vis_mmap->running = true;
1365 vis_mmap->buf_index = i;
1366 vis_mmap->rate = output.current_sample_rate;
1367 }
1368
1369 pthread_rwlock_unlock(&vis_mmap->rwlock);
1370 }
1371 }
1372 #endif
12881373
12891374 if (!silence) {
12901375 _buf_inc_readp(outputbuf, out_frames * BYTES_PER_FRAME);
13901475 const char *alsa_sample_fmt, bool mmap, unsigned max_rate, unsigned rt_priority) {
13911476 #endif
13921477 #if PORTAUDIO
1393 void output_init(log_level level, const char *device, unsigned output_buf_size, unsigned latency, int osx_playnice, unsigned max_rate) {
1478 void output_init(log_level level, const char *device, unsigned output_buf_size, unsigned latency, int osx_playnice, unsigned max_rate) {
13941479 PaError err;
13951480 #endif
13961481 loglevel = level;
15031588 UNLOCK;
15041589 }
15051590
1591 #if VISEXPORT
1592 void output_vis_init(u8_t *mac) {
1593 sprintf(vis_shm_path, "/squeezelite-%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
1594
1595 LOCK;
1596 vis_fd = shm_open(vis_shm_path, O_CREAT | O_RDWR, 0666);
1597 if (vis_fd != -1) {
1598 if (ftruncate(vis_fd, sizeof(struct vis_t)) == 0) {
1599 vis_mmap = (struct vis_t *)mmap(NULL, sizeof(struct vis_t), PROT_READ | PROT_WRITE, MAP_SHARED, vis_fd, 0);
1600 }
1601 }
1602
1603 if (vis_mmap > 0) {
1604 pthread_rwlockattr_t attr;
1605 pthread_rwlockattr_init(&attr);
1606 pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
1607 pthread_rwlock_init(&vis_mmap->rwlock, &attr);
1608 vis_mmap->buf_size = VIS_BUF_SIZE;
1609 vis_mmap->running = false;
1610 vis_mmap->rate = output.current_sample_rate;
1611 pthread_rwlockattr_destroy(&attr);
1612 LOG_INFO("opened visulizer shared memory as %s", vis_shm_path);
1613 } else {
1614 LOG_WARN("unable to open visualizer shared memory");
1615 vis_mmap = NULL;
1616 }
1617 UNLOCK;
1618 }
1619 #endif
1620
15061621 void output_flush(void) {
15071622 LOG_INFO("flush output buffer");
15081623 buf_flush(outputbuf);
15461661 UNLOCK;
15471662 #endif
15481663
1664 #if VISEXPORT
1665 if (vis_mmap) {
1666 pthread_rwlock_destroy(&vis_mmap->rwlock);
1667 munmap(vis_mmap, sizeof(struct vis_t));
1668 }
1669
1670 if (vis_fd != -1) {
1671 shm_unlink(vis_shm_path);
1672 close(vis_fd);
1673 }
1674 #endif
1675
15491676 buf_destroy(outputbuf);
15501677 }
7777 #else
7878 #undef FFMPEG
7979 #define FFMPEG 0
80 #endif
81
82 #if LINUX && defined(VISEXPORT)
83 #undef VISEXPORT
84 #define VISEXPORT 1 // visulizer export support uses linux shared memory
85 #else
86 #undef VISEXPORT
87 #define VISEXPORT 0
8088 #endif
8189
8290 // dynamically loaded libraries
487495 #if PORTAUDIO
488496 void output_init(log_level level, const char *device, unsigned output_buf_size, unsigned latency, int osx_playnice, unsigned max_rate);
489497 #endif
498 #if VISEXPORT
499 void output_vis_init(u8_t *mac);
500 #endif
490501 void output_flush(void);
491502 void output_close(void);
492503 // _* called with mutex locked