48 #include <stdio.h> |
48 #include <stdio.h> |
49 #include <sys/types.h> |
49 #include <sys/types.h> |
50 #include <sys/ioctl.h> |
50 #include <sys/ioctl.h> |
51 #include <fcntl.h> |
51 #include <fcntl.h> |
52 #include <unistd.h> |
52 #include <unistd.h> |
|
53 |
|
54 #define HEADPHONE_STATE_FILE "/sys/devices/platform/gpio-switch/headphone/state" |
|
55 #define HEADPHONE_CONNECTED_STATE "connected" |
|
56 #define HEADPHONE_DISCONNECTED_STATE "disconnected" |
|
57 |
|
58 #define FMRXENABLER_DBUS_SERVICE "de.pycage.FMRXEnabler" |
|
59 #define FMRXENABLER_DBUS_OBJ_PATH "/de/pycage/FMRXEnabler" |
|
60 #define FMRXENABLER_DBUS_IFACE_NAME "de.pycage.FMRXEnabler" |
|
61 |
|
62 gboolean |
|
63 state_file_changed(GIOChannel* source, GIOCondition /*condition*/, gpointer data) |
|
64 { |
|
65 V4LRadioControl* radioControl = (V4LRadioControl*)data; |
|
66 gchar* result; |
|
67 |
|
68 g_io_channel_seek_position(source, 0, G_SEEK_SET, NULL); |
|
69 g_io_channel_read_line(source, &result, NULL, NULL, NULL); |
|
70 g_strstrip(result); |
|
71 |
|
72 if (g_ascii_strcasecmp(result, HEADPHONE_DISCONNECTED_STATE) == 0) { |
|
73 radioControl->enablePipeline(false); |
|
74 } else if (g_ascii_strcasecmp(result, HEADPHONE_CONNECTED_STATE) == 0) { |
|
75 // Wait 400ms until audio is routed again to headphone to prevent sound coming from speakers |
|
76 QTimer::singleShot(400,radioControl,SLOT(enablePipeline())); |
|
77 } |
|
78 |
|
79 #ifdef MULTIMEDIA_MAEMO_DEBUG |
|
80 qDebug() << "Headphone is now" << result; |
|
81 #endif |
|
82 |
|
83 g_free(result); |
|
84 return true; |
|
85 } |
53 |
86 |
54 V4LRadioControl::V4LRadioControl(QObject *parent) |
87 V4LRadioControl::V4LRadioControl(QObject *parent) |
55 : QRadioTunerControl(parent) |
88 : QRadioTunerControl(parent) |
56 , fd(1) |
89 , fd(1) |
57 , m_error(false) |
90 , m_error(false) |
62 , scanning(false) |
95 , scanning(false) |
63 , currentBand(QRadioTuner::FM) |
96 , currentBand(QRadioTuner::FM) |
64 , pipeline(0) |
97 , pipeline(0) |
65 { |
98 { |
66 if (QDBusConnection::systemBus().isConnected()) { |
99 if (QDBusConnection::systemBus().isConnected()) { |
67 FMRXEnablerIFace = new QDBusInterface("de.pycage.FMRXEnabler", |
100 FMRXEnablerIFace = new QDBusInterface(FMRXENABLER_DBUS_SERVICE, |
68 "/de/pycage/FMRXEnabler", |
101 FMRXENABLER_DBUS_OBJ_PATH, |
69 "de.pycage.FMRXEnabler", |
102 FMRXENABLER_DBUS_IFACE_NAME, |
70 QDBusConnection::systemBus()); |
103 QDBusConnection::systemBus()); |
|
104 } |
|
105 |
|
106 createGstPipeline(); |
|
107 |
|
108 GIOChannel* headphoneStateFile = NULL; |
|
109 headphoneStateFile = g_io_channel_new_file(HEADPHONE_STATE_FILE, "r", NULL); |
|
110 if (headphoneStateFile != NULL) { |
|
111 g_io_add_watch(headphoneStateFile, G_IO_PRI, state_file_changed, this); |
|
112 } else { |
|
113 #ifdef MULTIMEDIA_MAEMO_DEBUG |
|
114 qWarning() << QString("File %1 can't be read!").arg(HEADPHONE_STATE_FILE) ; |
|
115 qWarning() << "Monitoring headphone state isn't possible!"; |
|
116 #endif |
71 } |
117 } |
72 |
118 |
73 enableFMRX(); |
119 enableFMRX(); |
74 createGstPipeline(); |
|
75 initRadio(); |
120 initRadio(); |
76 setupHeadPhone(); |
121 setupHeadPhone(); |
77 |
122 |
78 setMuted(false); |
123 setMuted(false); |
79 |
124 |
80 timer = new QTimer(this); |
125 timer = new QTimer(this); |
81 timer->setInterval(200); |
126 timer->setInterval(200); |
82 connect(timer,SIGNAL(timeout()),this,SLOT(search())); |
127 connect(timer,SIGNAL(timeout()),this,SLOT(search())); |
83 timer->start(); |
|
84 |
128 |
85 tickTimer = new QTimer(this); |
129 tickTimer = new QTimer(this); |
86 tickTimer->setInterval(10000); |
130 tickTimer->setInterval(10000); |
87 connect(tickTimer,SIGNAL(timeout()),this,SLOT(enableFMRX())); |
131 connect(tickTimer,SIGNAL(timeout()),this,SLOT(enableFMRX())); |
88 tickTimer->start(); |
132 tickTimer->start(); |
98 |
142 |
99 if(fd > 0) |
143 if(fd > 0) |
100 ::close(fd); |
144 ::close(fd); |
101 } |
145 } |
102 |
146 |
|
147 void V4LRadioControl::enablePipeline(bool enable) |
|
148 { |
|
149 if (enable == true) |
|
150 gst_element_set_state (pipeline, GST_STATE_PLAYING); |
|
151 else |
|
152 gst_element_set_state (pipeline, GST_STATE_NULL); |
|
153 } |
|
154 |
103 void V4LRadioControl::enableFMRX() |
155 void V4LRadioControl::enableFMRX() |
104 { |
156 { |
105 if (FMRXEnablerIFace && FMRXEnablerIFace->isValid()) { |
157 if (FMRXEnablerIFace && FMRXEnablerIFace->isValid()) { |
106 FMRXEnablerIFace->call("request"); // Return value ignored |
158 FMRXEnablerIFace->call("request"); // Return value ignored |
107 } |
159 } |
133 bool V4LRadioControl::isAvailable() const |
185 bool V4LRadioControl::isAvailable() const |
134 { |
186 { |
135 return available; |
187 return available; |
136 } |
188 } |
137 |
189 |
138 QtMediaServices::AvailabilityError V4LRadioControl::availabilityError() const |
190 QtMultimedia::AvailabilityError V4LRadioControl::availabilityError() const |
139 { |
191 { |
140 if (fd > 0) |
192 if (fd > 0) |
141 return QtMediaServices::NoError; |
193 return QtMultimedia::NoError; |
142 else |
194 else |
143 return QtMediaServices::ResourceError; |
195 return QtMultimedia::ResourceError; |
144 } |
196 } |
145 |
197 |
146 QRadioTuner::State V4LRadioControl::state() const |
198 QRadioTuner::State V4LRadioControl::state() const |
147 { |
199 { |
148 return fd > 0 ? QRadioTuner::ActiveState : QRadioTuner::StoppedState; |
200 return fd > 0 ? QRadioTuner::ActiveState : QRadioTuner::StoppedState; |
262 freq.frequency = (int)(f/62500); |
314 freq.frequency = (int)(f/62500); |
263 } |
315 } |
264 ::ioctl(fd, VIDIOC_S_FREQUENCY, &freq); |
316 ::ioctl(fd, VIDIOC_S_FREQUENCY, &freq); |
265 currentFreq = f; |
317 currentFreq = f; |
266 emit frequencyChanged(currentFreq); |
318 emit frequencyChanged(currentFreq); |
|
319 |
|
320 int signal = signalStrength(); |
|
321 if(sig != signal) { |
|
322 sig = signal; |
|
323 emit signalStrengthChanged(sig); |
|
324 } |
267 } |
325 } |
268 } |
326 } |
269 } |
327 } |
270 |
328 |
271 bool V4LRadioControl::isStereo() const |
329 bool V4LRadioControl::isStereo() const |
379 if (elem) |
437 if (elem) |
380 volume = vol(elem); |
438 volume = vol(elem); |
381 |
439 |
382 snd_hctl_close(hctl); |
440 snd_hctl_close(hctl); |
383 |
441 |
384 return (volume/63.0) * 100; |
442 return (volume/118.0) * 100; |
385 } |
443 } |
386 |
444 |
387 void V4LRadioControl::setVolume(int volume) |
445 void V4LRadioControl::setVolume(int volume) |
388 { |
446 { |
389 |
447 int vol = (volume / 100.0) * 118; // 118 is a headphone max setting |
390 int vol = (volume / 100.0) * 63; // 63 is a headphone max setting |
|
391 callAmixer("Line DAC Playback Volume", QString().setNum(vol)+QString(",")+QString().setNum(vol)); |
448 callAmixer("Line DAC Playback Volume", QString().setNum(vol)+QString(",")+QString().setNum(vol)); |
392 } |
449 } |
393 |
450 |
394 bool V4LRadioControl::isMuted() const |
451 bool V4LRadioControl::isMuted() const |
395 { |
452 { |
410 |
467 |
411 settings["Jack Function"] = "Headset"; |
468 settings["Jack Function"] = "Headset"; |
412 settings["Left DAC_L1 Mixer HP Switch"] = "off"; |
469 settings["Left DAC_L1 Mixer HP Switch"] = "off"; |
413 settings["Right DAC_R1 Mixer HP Switch"] = "off"; |
470 settings["Right DAC_R1 Mixer HP Switch"] = "off"; |
414 settings["Line DAC Playback Switch"] = "on"; |
471 settings["Line DAC Playback Switch"] = "on"; |
415 settings["Line DAC Playback Volume"] = "63,63"; // Volume is set to 100% |
472 settings["Line DAC Playback Volume"] = "118,118"; // Volume is set to 100% |
416 settings["HPCOM DAC Playback Switch"] = "off"; |
473 settings["HPCOM DAC Playback Switch"] = "off"; |
417 settings["Left DAC_L1 Mixer HP Switch"] = "off"; |
474 settings["Left DAC_L1 Mixer HP Switch"] = "off"; |
418 settings["Left DAC_L1 Mixer Line Switch"] = "on"; |
475 settings["Left DAC_L1 Mixer Line Switch"] = "on"; |
419 settings["Right DAC_R1 Mixer HP Switch"] = "off"; |
476 settings["Right DAC_R1 Mixer HP Switch"] = "off"; |
420 settings["Right DAC_R1 Mixer Line Switch"] = "on"; |
477 settings["Right DAC_R1 Mixer Line Switch"] = "on"; |
478 count = snd_ctl_elem_info_get_count(info); |
535 count = snd_ctl_elem_info_get_count(info); |
479 |
536 |
480 snd_ctl_elem_value_set_id(control, id); |
537 snd_ctl_elem_value_set_id(control, id); |
481 |
538 |
482 tmp = 0; |
539 tmp = 0; |
483 for (int idx = 0; idx < count && idx < 128; idx++) |
540 for (uint idx = 0; idx < count && idx < 128; idx++) |
484 { |
541 { |
485 switch (type) |
542 switch (type) |
486 { |
543 { |
487 case SND_CTL_ELEM_TYPE_BOOLEAN: |
544 case SND_CTL_ELEM_TYPE_BOOLEAN: |
|
545 #ifdef MULTIMEDIA_MAEMO_DEBUG |
488 qDebug() << "SND_CTL_ELEM_TYPE_BOOLEAN" << SND_CTL_ELEM_TYPE_BOOLEAN; |
546 qDebug() << "SND_CTL_ELEM_TYPE_BOOLEAN" << SND_CTL_ELEM_TYPE_BOOLEAN; |
|
547 #endif |
489 if ((value == "on") ||(value == "1")) |
548 if ((value == "on") ||(value == "1")) |
490 { |
549 { |
491 tmp = 1; |
550 tmp = 1; |
492 } |
551 } |
493 snd_ctl_elem_value_set_boolean(control, idx, tmp); |
552 snd_ctl_elem_value_set_boolean(control, idx, tmp); |
495 case SND_CTL_ELEM_TYPE_ENUMERATED: |
554 case SND_CTL_ELEM_TYPE_ENUMERATED: |
496 tmp = getEnumItemIndex(handle, info, value); |
555 tmp = getEnumItemIndex(handle, info, value); |
497 snd_ctl_elem_value_set_enumerated(control, idx, tmp); |
556 snd_ctl_elem_value_set_enumerated(control, idx, tmp); |
498 break; |
557 break; |
499 case SND_CTL_ELEM_TYPE_INTEGER: |
558 case SND_CTL_ELEM_TYPE_INTEGER: |
|
559 #ifdef MULTIMEDIA_MAEMO_DEBUG |
500 qDebug() << "SND_CTL_ELEM_TYPE_INTEGER" << SND_CTL_ELEM_TYPE_INTEGER; |
560 qDebug() << "SND_CTL_ELEM_TYPE_INTEGER" << SND_CTL_ELEM_TYPE_INTEGER; |
|
561 #endif |
501 tmp = atoi(value.toAscii()); |
562 tmp = atoi(value.toAscii()); |
502 if (tmp < snd_ctl_elem_info_get_min(info)) |
563 if (tmp < snd_ctl_elem_info_get_min(info)) |
503 tmp = snd_ctl_elem_info_get_min(info); |
564 tmp = snd_ctl_elem_info_get_min(info); |
504 else if (tmp > snd_ctl_elem_info_get_max(info)) |
565 else if (tmp > snd_ctl_elem_info_get_max(info)) |
505 tmp = snd_ctl_elem_info_get_max(info); |
566 tmp = snd_ctl_elem_info_get_max(info); |
598 return QString(); |
662 return QString(); |
599 } |
663 } |
600 |
664 |
601 void V4LRadioControl::search() |
665 void V4LRadioControl::search() |
602 { |
666 { |
|
667 if(!scanning) return; |
|
668 |
|
669 if(forward) { |
|
670 setFrequency(currentFreq+step); |
|
671 } else { |
|
672 setFrequency(currentFreq-step); |
|
673 } |
|
674 |
603 int signal = signalStrength(); |
675 int signal = signalStrength(); |
604 if(sig != signal) { |
676 if(sig != signal) { |
605 sig = signal; |
677 sig = signal; |
606 emit signalStrengthChanged(sig); |
678 emit signalStrengthChanged(sig); |
607 } |
679 } |
608 |
680 |
609 if(!scanning) return; |
|
610 |
|
611 if (signal > 25) { |
681 if (signal > 25) { |
612 cancelSearch(); |
682 cancelSearch(); |
613 return; |
683 return; |
614 } |
684 } |
615 |
|
616 if(forward) { |
|
617 setFrequency(currentFreq+step); |
|
618 } else { |
|
619 setFrequency(currentFreq-step); |
|
620 } |
|
621 emit signalStrengthChanged(signalStrength()); |
|
622 } |
685 } |
623 |
686 |
624 bool V4LRadioControl::initRadio() |
687 bool V4LRadioControl::initRadio() |
625 { |
688 { |
626 v4l2_tuner tuner; |
689 v4l2_tuner tuner; |
635 |
698 |
636 if(fd != -1) { |
699 if(fd != -1) { |
637 // Capabilites |
700 // Capabilites |
638 memset(&cap, 0, sizeof(cap)); |
701 memset(&cap, 0, sizeof(cap)); |
639 if(::ioctl(fd, VIDIOC_QUERYCAP, &cap ) >= 0) { |
702 if(::ioctl(fd, VIDIOC_QUERYCAP, &cap ) >= 0) { |
640 if(((cap.capabilities & V4L2_CAP_RADIO) == 0) && ((cap.capabilities & V4L2_CAP_AUDIO) == 0)) |
703 available = true; |
641 available = true; |
|
642 } |
704 } |
643 |
705 |
644 tuner.index = 0; |
706 tuner.index = 0; |
645 |
707 |
646 if (ioctl(fd, VIDIOC_G_TUNER, &tuner) < 0) { |
708 if (ioctl(fd, VIDIOC_G_TUNER, &tuner) < 0) { |