366 fatal = true; |
367 fatal = true; |
367 errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err); |
368 errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err); |
368 } |
369 } |
369 } |
370 } |
370 if ( !fatal ) { |
371 if ( !fatal ) { |
|
372 unsigned int maxBufferTime = 0; |
|
373 unsigned int minBufferTime = 0; |
|
374 unsigned int maxPeriodTime = 0; |
|
375 unsigned int minPeriodTime = 0; |
|
376 |
|
377 err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &maxBufferTime, &dir); |
|
378 if ( err >= 0) |
|
379 err = snd_pcm_hw_params_get_buffer_time_min(hwparams, &minBufferTime, &dir); |
|
380 if ( err >= 0) |
|
381 err = snd_pcm_hw_params_get_period_time_max(hwparams, &maxPeriodTime, &dir); |
|
382 if ( err >= 0) |
|
383 err = snd_pcm_hw_params_get_period_time_min(hwparams, &minPeriodTime, &dir); |
|
384 |
|
385 if ( err < 0 ) { |
|
386 fatal = true; |
|
387 errMessage = QString::fromLatin1("QAudioOutput: buffer/period min and max: err = %1").arg(err); |
|
388 } else { |
|
389 if (maxBufferTime < buffer_time || buffer_time < minBufferTime || maxPeriodTime < period_time || minPeriodTime > period_time) { |
|
390 #ifdef DEBUG_AUDIO |
|
391 qDebug()<<"defaults out of range"; |
|
392 qDebug()<<"pmin="<<minPeriodTime<<", pmax="<<maxPeriodTime<<", bmin="<<minBufferTime<<", bmax="<<maxBufferTime; |
|
393 #endif |
|
394 period_time = minPeriodTime; |
|
395 if (period_time*4 <= maxBufferTime) { |
|
396 // Use 4 periods if possible |
|
397 buffer_time = period_time*4; |
|
398 chunks = 4; |
|
399 } else if (period_time*2 <= maxBufferTime) { |
|
400 // Use 2 periods if possible |
|
401 buffer_time = period_time*2; |
|
402 chunks = 2; |
|
403 } else { |
|
404 qWarning()<<"QAudioOutput: alsa only supports single period!"; |
|
405 fatal = true; |
|
406 } |
|
407 #ifdef DEBUG_AUDIO |
|
408 qDebug()<<"used: buffer_time="<<buffer_time<<", period_time="<<period_time; |
|
409 #endif |
|
410 } |
|
411 } |
|
412 } |
|
413 if ( !fatal ) { |
371 err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir); |
414 err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir); |
372 if ( err < 0 ) { |
415 if ( err < 0 ) { |
373 fatal = true; |
416 fatal = true; |
374 errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err); |
417 errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err); |
375 } |
418 } |
376 } |
419 } |
377 if ( !fatal ) { |
420 if ( !fatal ) { |
378 err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir); |
421 err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir); |
379 if ( err < 0 ) { |
422 if ( err < 0 ) { |
492 // Only write space worth |
535 // Only write space worth |
493 frames = snd_pcm_bytes_to_frames( handle, (int)space ); |
536 frames = snd_pcm_bytes_to_frames( handle, (int)space ); |
494 err = snd_pcm_writei( handle, data, frames ); |
537 err = snd_pcm_writei( handle, data, frames ); |
495 } |
538 } |
496 if(err > 0) { |
539 if(err > 0) { |
497 totalTimeValue += err*1000000/settings.frequency(); |
540 totalTimeValue += err; |
498 resuming = false; |
541 resuming = false; |
499 errorState = QAudio::NoError; |
542 errorState = QAudio::NoError; |
500 deviceState = QAudio::ActiveState; |
543 if (deviceState != QAudio::ActiveState) { |
|
544 deviceState = QAudio::ActiveState; |
|
545 emit stateChanged(deviceState); |
|
546 } |
501 return snd_pcm_frames_to_bytes( handle, err ); |
547 return snd_pcm_frames_to_bytes( handle, err ); |
502 } else |
548 } else |
503 err = xrun_recovery(err); |
549 err = xrun_recovery(err); |
504 |
550 |
505 if(err < 0) { |
551 if(err < 0) { |
560 xrun_recovery(err); |
606 xrun_recovery(err); |
561 |
607 |
562 bytesAvailable = (int)snd_pcm_frames_to_bytes(handle, buffer_frames); |
608 bytesAvailable = (int)snd_pcm_frames_to_bytes(handle, buffer_frames); |
563 } |
609 } |
564 resuming = true; |
610 resuming = true; |
565 if(pullMode) |
611 |
566 deviceState = QAudio::ActiveState; |
612 deviceState = QAudio::ActiveState; |
567 else |
|
568 deviceState = QAudio::IdleState; |
|
569 |
613 |
570 errorState = QAudio::NoError; |
614 errorState = QAudio::NoError; |
571 timer->start(period_time/1000); |
615 timer->start(period_time/1000); |
572 emit stateChanged(deviceState); |
616 emit stateChanged(deviceState); |
573 } |
617 } |
635 l = audioSource->read(audioBuffer,snd_pcm_frames_to_bytes(handle, input)); |
680 l = audioSource->read(audioBuffer,snd_pcm_frames_to_bytes(handle, input)); |
636 if(l > 0) { |
681 if(l > 0) { |
637 // Got some data to output |
682 // Got some data to output |
638 if(deviceState != QAudio::ActiveState) |
683 if(deviceState != QAudio::ActiveState) |
639 return true; |
684 return true; |
640 write(audioBuffer,l); |
685 qint64 bytesWritten = write(audioBuffer,l); |
|
686 if (bytesWritten != l) |
|
687 audioSource->seek(audioSource->pos()-(l-bytesWritten)); |
641 bytesAvailable = bytesFree(); |
688 bytesAvailable = bytesFree(); |
642 |
689 |
643 } else if(l == 0) { |
690 } else if(l == 0) { |
644 // Did not get any data to output |
691 // Did not get any data to output |
645 bytesAvailable = bytesFree(); |
692 bytesAvailable = bytesFree(); |
646 if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) { |
693 if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) { |
647 // Underrun |
694 // Underrun |
|
695 if (deviceState != QAudio::IdleState) { |
|
696 errorState = QAudio::UnderrunError; |
|
697 deviceState = QAudio::IdleState; |
|
698 emit stateChanged(deviceState); |
|
699 } |
|
700 } |
|
701 |
|
702 } else if(l < 0) { |
|
703 close(); |
|
704 errorState = QAudio::IOError; |
|
705 emit stateChanged(deviceState); |
|
706 } |
|
707 } else { |
|
708 bytesAvailable = bytesFree(); |
|
709 if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) { |
|
710 // Underrun |
|
711 if (deviceState != QAudio::IdleState) { |
648 errorState = QAudio::UnderrunError; |
712 errorState = QAudio::UnderrunError; |
649 deviceState = QAudio::IdleState; |
713 deviceState = QAudio::IdleState; |
650 emit stateChanged(deviceState); |
714 emit stateChanged(deviceState); |
651 } |
715 } |
652 |
716 } |
653 } else if(l < 0) { |
717 } |
654 close(); |
|
655 errorState = QAudio::IOError; |
|
656 emit stateChanged(deviceState); |
|
657 } |
|
658 } else |
|
659 bytesAvailable = bytesFree(); |
|
660 |
718 |
661 if(deviceState != QAudio::ActiveState) |
719 if(deviceState != QAudio::ActiveState) |
662 return true; |
720 return true; |
663 |
721 |
664 if((timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { |
722 if((timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { |
669 return true; |
727 return true; |
670 } |
728 } |
671 |
729 |
672 qint64 QAudioOutputPrivate::elapsedUSecs() const |
730 qint64 QAudioOutputPrivate::elapsedUSecs() const |
673 { |
731 { |
674 if(!handle) |
|
675 return 0; |
|
676 |
|
677 if (deviceState == QAudio::StoppedState) |
732 if (deviceState == QAudio::StoppedState) |
678 return 0; |
733 return 0; |
679 |
734 |
680 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) |
|
681 snd_pcm_status_t* status; |
|
682 snd_pcm_status_alloca(&status); |
|
683 |
|
684 snd_timestamp_t t1,t2; |
|
685 if( snd_pcm_status(handle, status) >= 0) { |
|
686 snd_pcm_status_get_tstamp(status,&t1); |
|
687 snd_pcm_status_get_trigger_tstamp(status,&t2); |
|
688 t1.tv_sec-=t2.tv_sec; |
|
689 |
|
690 signed long l = (signed long)t1.tv_usec - (signed long)t2.tv_usec; |
|
691 if(l < 0) { |
|
692 t1.tv_sec--; |
|
693 l = -l; |
|
694 l %= 1000000; |
|
695 } |
|
696 return ((t1.tv_sec * 1000000)+l); |
|
697 } else |
|
698 return 0; |
|
699 #else |
|
700 return clockStamp.elapsed()*1000; |
735 return clockStamp.elapsed()*1000; |
701 #endif |
|
702 return 0; |
|
703 } |
736 } |
704 |
737 |
705 void QAudioOutputPrivate::reset() |
738 void QAudioOutputPrivate::reset() |
706 { |
739 { |
707 if(handle) |
740 if(handle) |