~ubuntu-branches/ubuntu/natty/kdemultimedia/natty-updates

« back to all changes in this revision

Viewing changes to kmix/backends/mixer_pulse.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-04-19 16:01:21 UTC
  • Revision ID: james.westby@ubuntu.com-20110419160121-jw7ffrspt26u3kt2
Tags: 4:4.6.2-0ubuntu2
* Add kubuntu_03_kmix_pulseaudio_fixes.diff: Cherry-pick several PulseAudio
  related KMix fixes that will be part of KDE 4.6.3.
  - Fixes very high CPU usage. (LP: #720882)
  - Fixes memory leaks. (LP: #676780)

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
#define KMIXPA_APP_CAPTURE  3
37
37
#define KMIXPA_WIDGET_MAX KMIXPA_APP_CAPTURE
38
38
 
 
39
#define KMIXPA_EVENT_KEY "sink-input-by-media-role:event"
 
40
 
39
41
static unsigned int refcount = 0;
40
42
static pa_glib_mainloop *s_mainloop = NULL;
41
43
static pa_context *s_context = NULL;
189
191
 
190
192
    devinfo s;
191
193
    s.index = s.device_index = i->index;
192
 
    s.name = QString(i->name).replace(' ', '_');
 
194
    s.name = QString::fromUtf8(i->name).replace(' ', '_');
193
195
    s.description = QString::fromUtf8(i->description);
194
196
    s.icon_name = QString::fromUtf8(pa_proplist_gets(i->proplist, PA_PROP_DEVICE_ICON_NAME));
195
197
    s.volume = i->volume;
242
244
 
243
245
    devinfo s;
244
246
    s.index = s.device_index = i->index;
245
 
    s.name = QString(i->name).replace(' ', '_');
 
247
    s.name = QString::fromUtf8(i->name).replace(' ', '_');
246
248
    s.description = QString::fromUtf8(i->description);
247
249
    s.icon_name = QString::fromUtf8(pa_proplist_gets(i->proplist, PA_PROP_DEVICE_ICON_NAME));
248
250
    s.volume = i->volume;
307
309
 
308
310
    const char *t;
309
311
    if ((t = pa_proplist_gets(i->proplist, "module-stream-restore.id"))) {
310
 
        if (strcmp(t, "sink-input-by-media-role:event") == 0) {
 
312
        if (strcmp(t, KMIXPA_EVENT_KEY) == 0) {
311
313
            kWarning(67100) << "Ignoring sink-input due to it being designated as an event and thus handled by the Event slider";
312
314
            return;
313
315
        }
314
316
    }
315
317
 
316
 
    QString prefix = QString("%1: ").arg(i18n("Unknown Application"));
 
318
    QString appname = i18n("Unknown Application");
317
319
    if (clients.contains(i->client))
318
 
        prefix = QString("%1: ").arg(clients[i->client]);
 
320
        appname = clients[i->client];
 
321
 
 
322
    QString prefix = QString("%1: ").arg(appname);
319
323
 
320
324
    devinfo s;
321
325
    s.index = i->index;
322
326
    s.device_index = i->sink;
323
327
    s.description = prefix + QString::fromUtf8(i->name);
324
 
    s.name = QString("stream:") + i->index;
 
328
    s.name = QString("stream:") + QString::number(i->index); //appname.replace(' ', '_').toLower();
325
329
    s.icon_name = getIconNameFromProplist(i->proplist);
326
330
    s.volume = i->volume;
327
331
    s.channel_map = i->channel_map;
328
332
    s.mute = !!i->mute;
329
 
    s.stream_restore_rule = t;
 
333
    s.stream_restore_rule = QString::fromUtf8(t);
330
334
 
331
335
    translateMasksAndMaps(s);
332
336
 
370
374
        return;
371
375
    }
372
376
 
373
 
    QString prefix = QString("%1: ").arg(i18n("Unknown Application"));
 
377
    QString appname = i18n("Unknown Application");
374
378
    if (clients.contains(i->client))
375
 
        prefix = QString("%1: ").arg(clients[i->client]);
 
379
        appname = clients[i->client];
 
380
 
 
381
    QString prefix = QString("%1: ").arg(appname);
376
382
 
377
383
    devinfo s;
378
384
    s.index = i->index;
379
385
    s.device_index = i->source;
380
386
    s.description = prefix + QString::fromUtf8(i->name);
381
 
    s.name = QString("stream:") + i->index;
 
387
    s.name = QString("stream:") + QString::number(i->index); //appname.replace(' ', '_').toLower();
382
388
    s.icon_name = getIconNameFromProplist(i->proplist);
383
389
    //s.volume = i->volume;
384
390
    s.volume = captureDevices[i->source].volume;
385
391
    s.channel_map = i->channel_map;
386
392
    //s.mute = !!i->mute;
387
393
    s.mute = captureDevices[i->source].mute;
388
 
    s.stream_restore_rule = pa_proplist_gets(i->proplist, "module-stream-restore.id");
 
394
    s.stream_restore_rule = QString::fromUtf8(pa_proplist_gets(i->proplist, "module-stream-restore.id"));
389
395
 
390
396
    translateMasksAndMaps(s);
391
397
 
407
413
}
408
414
 
409
415
 
410
 
static devinfo create_role_devinfo(const char* name) {
 
416
static devinfo create_role_devinfo(QString name) {
411
417
 
412
418
    Q_ASSERT(s_RestoreRules.contains(name));
413
419
 
436
442
 
437
443
    if (eol > 0) {
438
444
        dec_outstanding(c);
 
445
 
439
446
        // Special case: ensure that our media events exists.
440
447
        // On first login by a new users, this wont be in our database so we should create it.
441
 
        if (!outputRoles.contains(PA_INVALID_INDEX)) {
 
448
        if (!s_RestoreRules.contains(KMIXPA_EVENT_KEY)) {
442
449
            // Create a fake rule
443
450
            restoreRule rule;
444
451
            rule.channel_map.channels = 1;
447
454
            rule.volume.values[0] = PA_VOLUME_NORM;
448
455
            rule.mute = false;
449
456
            rule.device = "";
450
 
            s_RestoreRules["sink-input-by-media-role:event"] = rule;
451
 
 
452
 
            devinfo s = create_role_devinfo("sink-input-by-media-role:event");
453
 
            outputRoles[s.index] = s;
454
 
            kDebug(67100) << "Initialising restore rule for new user: " << s.description;
455
 
 
456
 
            if (s_mixers.contains(KMIXPA_APP_PLAYBACK))
 
457
            s_RestoreRules[KMIXPA_EVENT_KEY] = rule;
 
458
            kDebug(67100) << "Initialising restore rule for new user: " << i18n("Event Sounds");
 
459
        }
 
460
 
 
461
        if (s_mixers.contains(KMIXPA_APP_PLAYBACK)) {
 
462
            // If we have rules, it will be created below... but if no rules
 
463
            // then we add it here.
 
464
            if (!outputRoles.contains(PA_INVALID_INDEX)) {
 
465
                devinfo s = create_role_devinfo(KMIXPA_EVENT_KEY);
 
466
                outputRoles[s.index] = s;
 
467
 
457
468
                s_mixers[KMIXPA_APP_PLAYBACK]->addWidget(s.index);
458
 
        }
 
469
            }
459
470
 
460
 
        if (s_mixers.contains(KMIXPA_APP_PLAYBACK))
461
471
            s_mixers[KMIXPA_APP_PLAYBACK]->triggerUpdate();
 
472
        }
 
473
 
462
474
        return;
463
475
    }
464
476
 
465
 
    kDebug(67100) << "Got some info about restore rule: " << i->name << i->device;
 
477
 
 
478
    QString name = QString::fromUtf8(i->name);
 
479
    kDebug(67100) << QString("Got some info about restore rule: '%1' (Device: %2)").arg(name).arg(i->device ? i->device : "None");
466
480
    restoreRule rule;
467
481
    rule.channel_map = i->channel_map;
468
482
    rule.volume = i->volume;
469
483
    rule.mute = !!i->mute;
470
484
    rule.device = i->device;
471
 
    s_RestoreRules[i->name] = rule;
472
 
 
473
 
    // We only want to know about Sound Events for now...
474
 
    if (strcmp(i->name, "sink-input-by-media-role:event") == 0) {
475
 
        devinfo s = create_role_devinfo(i->name);
476
 
        bool is_new = !outputRoles.contains(s.index);
477
 
        outputRoles[s.index] = s;
478
 
 
479
 
        if (is_new && s_mixers.contains(KMIXPA_APP_PLAYBACK))
480
 
            s_mixers[KMIXPA_APP_PLAYBACK]->addWidget(s.index);
 
485
 
 
486
    if (rule.channel_map.channels < 1 && name == KMIXPA_EVENT_KEY) {
 
487
        // Stream restore rules may not have valid volumes/channel maps (as these are optional)
 
488
        // but we need a valid volume+channelmap for our events sounds so fix it up.
 
489
        rule.channel_map.channels = 1;
 
490
        rule.channel_map.map[0] = PA_CHANNEL_POSITION_MONO;
 
491
        rule.volume.channels = 1;
 
492
        rule.volume.values[0] = PA_VOLUME_NORM;
 
493
    }
 
494
 
 
495
    s_RestoreRules[name] = rule;
 
496
 
 
497
    if (s_mixers.contains(KMIXPA_APP_PLAYBACK)) {
 
498
        // We only want to know about Sound Events for now...
 
499
        if (name == KMIXPA_EVENT_KEY) {
 
500
            devinfo s = create_role_devinfo(name);
 
501
            bool is_new = !outputRoles.contains(s.index);
 
502
            outputRoles[s.index] = s;
 
503
 
 
504
            if (is_new)
 
505
                s_mixers[KMIXPA_APP_PLAYBACK]->addWidget(s.index);
 
506
        }
481
507
    }
482
508
}
483
509
 
788
814
        Volume v(dev.chanMask, PA_VOLUME_NORM, PA_VOLUME_MUTED, true, false);
789
815
        setVolumeFromPulse(v, dev);
790
816
        MixDevice* md = new MixDevice( _mixer, dev.name, dev.description, dev.icon_name, ms);
791
 
        md->setEthereal(true);
792
817
        md->addPlaybackVolume(v);
793
818
        md->setMuted(dev.mute);
794
819
        m_mixDevices.append(md);
1095
1120
                {
1096
1121
                    restoreRule &rule = s_RestoreRules[iter->stream_restore_rule];
1097
1122
                    pa_ext_stream_restore_info info;
1098
 
                    info.name = iter->stream_restore_rule.toAscii().constData();
 
1123
                    info.name = iter->stream_restore_rule.toUtf8().constData();
1099
1124
                    info.channel_map = rule.channel_map;
1100
1125
                    info.volume = genVolumeForPulse(*iter, md->playbackVolume());
1101
 
                    info.device = rule.device.isEmpty() ? NULL : rule.device.toAscii().constData();
 
1126
                    info.device = rule.device.isEmpty() ? NULL : rule.device.toUtf8().constData();
1102
1127
                    info.mute = (md->isMuted() ? 1 : 0);
1103
1128
 
1104
1129
                    pa_operation* o;
1153
1178
 
1154
1179
    // Lookup the stream index.
1155
1180
    uint32_t stream_index = PA_INVALID_INDEX;
1156
 
    const char* stream_restore_rule = NULL;
 
1181
    QString stream_restore_rule = "";
1157
1182
    devmap::iterator iter;
1158
1183
    devmap *map = get_widget_map(m_devnum);
1159
1184
    for (iter = map->begin(); iter != map->end(); ++iter) {
1160
1185
        if (iter->name == id) {
1161
1186
            stream_index = iter->index;
1162
 
            stream_restore_rule = iter->stream_restore_rule.isEmpty() ? NULL : iter->stream_restore_rule.toAscii().constData();
 
1187
            stream_restore_rule = iter->stream_restore_rule;
1163
1188
            break;
1164
1189
        }
1165
1190
    }
1171
1196
 
1172
1197
    if (destId.isEmpty()) {
1173
1198
        // We want to remove any specific device in the stream restore rule.
1174
 
        if (!stream_restore_rule || !s_RestoreRules.contains(stream_restore_rule)) {
 
1199
        if (stream_restore_rule.isEmpty() || !s_RestoreRules.contains(stream_restore_rule)) {
1175
1200
            kWarning(67100) <<  "Mixer_PULSE::moveStream(): Trying to set Automatic on a stream with no rule";
1176
1201
        } else {
1177
1202
            restoreRule &rule = s_RestoreRules[stream_restore_rule];
1178
1203
            pa_ext_stream_restore_info info;
1179
 
            info.name = stream_restore_rule;
 
1204
            info.name = stream_restore_rule.toUtf8().constData();
1180
1205
            info.channel_map = rule.channel_map;
1181
1206
            info.volume = rule.volume;
1182
1207
            info.device = NULL;
1192
1217
    } else {
1193
1218
        pa_operation* o;
1194
1219
        if (KMIXPA_APP_PLAYBACK == m_devnum) {
1195
 
            if (!(o = pa_context_move_sink_input_by_name(s_context, stream_index, destId.toAscii().constData(), NULL, NULL))) {
 
1220
            if (!(o = pa_context_move_sink_input_by_name(s_context, stream_index, destId.toUtf8().constData(), NULL, NULL))) {
1196
1221
                kWarning(67100) <<  "pa_context_move_sink_input_by_name() failed";
1197
1222
                return false;
1198
1223
            }
1199
1224
        } else {
1200
 
            if (!(o = pa_context_move_source_output_by_name(s_context, stream_index, destId.toAscii().constData(), NULL, NULL))) {
 
1225
            if (!(o = pa_context_move_source_output_by_name(s_context, stream_index, destId.toUtf8().constData(), NULL, NULL))) {
1201
1226
                kWarning(67100) <<  "pa_context_move_source_output_by_name() failed";
1202
1227
                return false;
1203
1228
            }