support output device on/off with portaudio, default to playnice on osx
Adrian Smith
10 years ago
466 | 466 | bool probe_thread_running = false; |
467 | 467 | |
468 | 468 | static void *pa_probe() { |
469 | // this is a hack to partially support hot plugging of devices | |
470 | // we rely on terminating and reinitalising PA to get an updated list of devices and use name for output.device | |
469 | bool output_off; | |
470 | LOCK; | |
471 | output_off = (output.state == OUTPUT_OFF); | |
472 | UNLOCK; | |
473 | ||
471 | 474 | while (probe_thread_running) { |
472 | LOG_INFO("probing device %s", output.device); | |
473 | 475 | LOCK; |
474 | Pa_Terminate(); | |
475 | Pa_Initialize(); | |
476 | pa.stream = NULL; | |
477 | if (pa_device_id(output.device) != -1) { | |
478 | LOG_INFO("found"); | |
479 | probe_thread_running = false; | |
480 | _pa_open(); | |
476 | if (output_off) { | |
477 | if (output.state != OUTPUT_OFF) { | |
478 | LOG_INFO("output on"); | |
479 | probe_thread_running = false; | |
480 | pa.stream = NULL; | |
481 | _pa_open(); | |
482 | } | |
481 | 483 | } else { |
482 | sleep(5); | |
484 | // this is a hack to partially support hot plugging of devices | |
485 | // we rely on terminating and reinitalising PA to get an updated list of devices and use name for output.device | |
486 | LOG_INFO("probing device %s", output.device); | |
487 | Pa_Terminate(); | |
488 | Pa_Initialize(); | |
489 | pa.stream = NULL; | |
490 | if (pa_device_id(output.device) != -1) { | |
491 | LOG_INFO("device reopen"); | |
492 | probe_thread_running = false; | |
493 | _pa_open(); | |
494 | } | |
483 | 495 | } |
484 | 496 | UNLOCK; |
497 | ||
498 | if (probe_thread_running) { | |
499 | sleep(output_off ? 1 : 5); | |
500 | } | |
485 | 501 | } |
486 | 502 | |
487 | 503 | return 0; |
513 | 529 | #if OSX |
514 | 530 | // enable pro mode which aims to avoid resampling if possible |
515 | 531 | // see http://code.google.com/p/squeezelite/issues/detail?id=11 & http://code.google.com/p/squeezelite/issues/detail?id=37 |
516 | // command line controls osx_playnice which is -1 if not specified, 0 or 1 | |
532 | // command line controls osx_playnice which is -1 if not specified, 0 or 1 - choose playnice if -1 or 1 | |
517 | 533 | PaMacCoreStreamInfo macInfo; |
518 | 534 | unsigned long streamInfoFlags; |
519 | if (output.osx_playnice == 1 || | |
520 | (output.osx_playnice == -1 && !strcmp(Pa_GetDeviceInfo(outputParameters.device)->name, "Built-in Output"))) { | |
535 | if (output.osx_playnice) { | |
521 | 536 | LOG_INFO("opening device in PlayNice mode"); |
522 | 537 | streamInfoFlags = paMacCorePlayNice; |
523 | 538 | } else { |
529 | 544 | #endif |
530 | 545 | } |
531 | 546 | |
532 | if (!err && | |
547 | if (!err && output.state != OUTPUT_OFF && | |
533 | 548 | (err = Pa_OpenStream(&pa.stream, NULL, &outputParameters, (double)output.current_sample_rate, paFramesPerBufferUnspecified, |
534 | 549 | paPrimeOutputBuffersUsingStreamCallback | paDitherOff, pa_callback, NULL)) != paNoError) { |
535 | 550 | LOG_WARN("error opening device %i - %s : %s", outputParameters.device, Pa_GetDeviceInfo(outputParameters.device)->name, |
536 | 551 | Pa_GetErrorText(err)); |
537 | 552 | } |
538 | 553 | |
539 | if (!err) { | |
554 | if (!err && output.state != OUTPUT_OFF) { | |
540 | 555 | LOG_INFO("opened device %i - %s at %u latency %u ms", outputParameters.device, Pa_GetDeviceInfo(outputParameters.device)->name, |
541 | 556 | (unsigned int)Pa_GetStreamInfo(pa.stream)->sampleRate, (unsigned int)(Pa_GetStreamInfo(pa.stream)->outputLatency * 1000)); |
542 | 557 | |
551 | 566 | } |
552 | 567 | } |
553 | 568 | |
554 | if (err && !probe_thread_running) { | |
569 | if ((err || output.state == OUTPUT_OFF) && !probe_thread_running) { | |
555 | 570 | // create a thread to probe for the device |
556 | 571 | #if LINUX || OSX |
557 | 572 | pthread_create(&probe_thread, NULL, pa_probe, NULL); |
1252 | 1267 | memset(optr, 0, (pa_frames_wanted - frames) * BYTES_PER_FRAME); |
1253 | 1268 | } |
1254 | 1269 | |
1255 | if (pa.rate != output.current_sample_rate) { | |
1270 | if (output.state == OUTPUT_OFF) { | |
1271 | LOG_INFO("output off"); | |
1272 | UNLOCK; | |
1273 | return paComplete; | |
1274 | } else if (pa.rate != output.current_sample_rate) { | |
1256 | 1275 | UNLOCK; |
1257 | 1276 | return paComplete; |
1258 | 1277 | } else { |