2013-03-01 69 views
2

當我嘗試使用ALSA庫時,我獲得了C代碼的奇怪行爲。 我用這個代碼來生成設備的SID使用alsalib時出現奇怪的C行爲

snd_mixer_selem_id_t* 
getSid(){ 
    snd_mixer_selem_id_t *sid; 
    snd_mixer_selem_id_alloca(&sid); 
    snd_mixer_selem_id_set_index(sid,0); 
    snd_mixer_selem_id_set_name(sid, selem_name); 

    return sid; 
} 

然後我試圖通過

snd_mixer_t *handle = getHandle(); 
snd_mixer_selem_id_t *sid = getSid(); 

snd_mixer_elem_t *elem = snd_mixer_find_selem(handle,sid); 

getHandle()進入電影這個功能是等效函數來獲取卡的處理程序,但是這一項工作。 奇怪的是,如果我在使用snd_mixer_find_selem函數之前直接使用函數的代碼,它正在工作。我不得不說,我是C新手,這是我的第一個項目之一,所以這可能是一個初學者與指針的錯誤。

的錯誤消息是simple.c:282: snd_mixer_selem_get_playback_volume_range: Assertion 'elem' failed.

因此,沒有人知道是什麼問題?

這裏是我使用的代碼的一個小例子:

#include <alsa/asoundlib.h> 

static const char *selem_name = "Master"; 
static const char *card = "default"; 

snd_mixer_t* 
getHandle(){ 
    snd_mixer_t *handle; 

    snd_mixer_open(&handle, 0); 
    snd_mixer_attach(handle, card); 
    snd_mixer_selem_register(handle, NULL, NULL); 
    snd_mixer_load(handle); 

    return handle; 
} 

snd_mixer_selem_id_t* 
getSid(){ 
    snd_mixer_selem_id_t *sid; 
    snd_mixer_selem_id_alloca(&sid); 
    snd_mixer_selem_id_set_index(sid,0); 
    snd_mixer_selem_id_set_name(sid, selem_name); 

    return sid; 
} 

void 
incMasterVol(long step){ // Step is a value in [-100,100] 
    long min,max,curr; 

    snd_mixer_t *handle = getHandle(); 

/*snd_mixer_open(&handle, 0); 
    snd_mixer_attach(handle, card); 
    snd_mixer_selem_register(handle, NULL, NULL); 
    snd_mixer_load(handle);*/ 

    snd_mixer_selem_id_t *sid; 
    snd_mixer_selem_id_alloca(&sid); 
    snd_mixer_selem_id_set_index(sid,0); 
    snd_mixer_selem_id_set_name(sid, selem_name); 

    snd_mixer_elem_t *elem = snd_mixer_find_selem(handle,sid); 

    snd_mixer_selem_get_playback_volume_range(elem, &min, &max); 
    snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_SIDE_LEFT, &curr); 
    curr = curr * 100/max; 
    if(curr + step > 100) 
    curr = 100; 
    else if(curr + step < 0) 
    curr = 0; 
    else 
    curr += step; 
    snd_mixer_selem_set_playback_volume_all(elem, curr * max/100); 

    snd_mixer_close(handle); 
} 

void 
toggleMasterVol(){ 
int swiVal; 
snd_mixer_t *handle = getHandle(); 
snd_mixer_elem_t *elem = snd_mixer_find_selem(handle,getSid()); 

snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_SIDE_LEFT, &swiVal); 
snd_mixer_selem_set_playback_switch_all(elem, !swiVal); 

snd_mixer_close(handle); 
} 

int 
main(int argc, char *argv[]){ 
    incMasterVol(5); 
} 
+0

我們需要一點點更多源代碼上下文來提出有用的建議。請擴展您發佈的源代碼,最好是展示該問題的最小功能示例。 – datenwolf 2013-03-01 12:45:20

+0

什麼是「奇怪的行爲」?你永遠不會描述當它不「工作」時會發生什麼。 – unwind 2013-03-01 13:11:46

+0

當使用'getSid'函數時,我得到上面發佈的錯誤消息。否則,它只是沒有任何錯誤地工作(當我使用註釋塊代替函數時)。 – domna 2013-03-01 13:18:48

回答

5

我認爲,從alloca()系統調用

alloca分配在棧幀中獲得,所以當getSid()回報您分配變量釋放你結束了一個dandling指針......(而當你把它的主要功能是因爲alloca頁頭的主要活動記錄的空間工作)

這只是一個建議,但我認爲你應該使用malloc(即在堆中分配空間,所以動態內存分配,直到你就可以調用free()

嘗試snd_mixer_selem_id_malloc()代替:)

+0

謝謝,這對我有效。但是我有另一個名爲'toggleMasterVol()'的函數,它可以與'getSid()'函數一起工作(我將它添加到上面的最小示例中)。你可能知道爲什麼這個電話有效嗎? – domna 2013-03-01 13:28:20

+0

一個dandling指針指向一個非有效的內存地址,從而使區域已經打上了內存管理器爲免費,但出於某種原因,該區域還可以繼續持有舊的價值,在這種情況下,你的功能得到正確的結構,但它只是運氣,如果你在你的'GETSID()'和'你toggleMasterVol()之間添加一些代碼'調用它也許會借給你的模擬誤差:d – SpectralWave 2013-03-01 14:00:56