Android6.0----关于USB麦克风框架

最近遇到一个问题:插入带麦克风的USB摄像头,摄像头可以正常输出图像但是没有声音,跟踪了一下整个框架记录一下

先从kernel入手:

kernel/sound/usb/card.c

当插入USB麦克风,USB Core会通过注册的usb_audio_ids 匹配到usb_audio_probe()函数

static struct usb_device_id usb_audio_ids [] = {

#include "quirks-table.h"

    { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),

      .bInterfaceClass = USB_CLASS_AUDIO,

      .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL },

    { } /* Terminating entry */

};

MODULE_DEVICE_TABLE(usb, usb_audio_ids);

/*

* entry point for linux usb interface

*/

static struct usb_driver usb_audio_driver = {

.name = "snd-usb-audio",

.probe = usb_audio_probe,

.disconnect = usb_audio_disconnect,

.suspend = usb_audio_suspend,

.resume = usb_audio_resume,

.id_table = usb_audio_ids,

.supports_autosuspend = 1,

};


static int usb_audio_probe(struct usb_interface *intf,

  const struct usb_device_id *id)

{

struct snd_usb_audio *chip;

chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id);

if (chip) {

usb_set_intfdata(intf, chip);

return 0;

} else

return -EIO;

}

snd_usb_audio_probe()函数会调用snd_usb_create_quirk()

static struct snd_usb_audio * snd_usb_audio_probe(struct usb_device *dev,struct usb_interface *intf,const struct usb_device_id *usb_id)

{

。。。。。。。。。。。。。。。。。。。

if (!chip->ctrl_intf)

chip->ctrl_intf = alts;

chip->txfr_quirk = 0;

err = 1; /* continue */

if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) {

/* need some special handlings */

if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0)

goto __error;

}

if (err > 0) {

/* create normal USB audio interfaces */

if (snd_usb_create_streams(chip, ifnum) < 0 ||

    snd_usb_create_mixer(chip, ifnum, ignore_ctl_error) < 0) {

goto __error;

}

}

/* we are allowed to call snd_card_register() many times */

if (snd_card_register(chip->card) < 0) {

goto __error;

}

。。。。。。。。。。。。。。。。。。。。。。。。。。

}


int snd_usb_create_quirk(struct snd_usb_audio *chip,struct usb_interface *iface,struct usb_driver *driver,const struct snd_usb_audio_quirk *quirk)

{

typedef int (*quirk_func_t)(struct snd_usb_audio *,

    struct usb_interface *,

    struct usb_driver *,

    const struct snd_usb_audio_quirk *);

static const quirk_func_t quirk_funcs[] = {

[QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,

[QUIRK_COMPOSITE] = create_composite_quirk,

[QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk,

[QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk,

[QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,

[QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,

[QUIRK_MIDI_NOVATION] = create_any_midi_quirk,

[QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk,

[QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,

[QUIRK_MIDI_CME] = create_any_midi_quirk,

[QUIRK_MIDI_AKAI] = create_any_midi_quirk,

[QUIRK_MIDI_FTDI] = create_any_midi_quirk,

[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,

[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,

[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,

[QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk,

[QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk,

};

if (quirk->type < QUIRK_TYPE_COUNT) {

return quirk_funcs[quirk->type](chip, iface, driver, quirk);

} else {

snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);

return -ENXIO;

}

}


static int create_uaxx_quirk(struct snd_usb_audio *chip,

    struct usb_interface *iface,

    struct usb_driver *driver,

    const struct snd_usb_audio_quirk *quirk)

{

。。。。。。

err = snd_usb_add_audio_stream(chip, stream, fp);

。。。。。。

}

int snd_usb_add_audio_stream(struct snd_usb_audio *chip,

    int stream,

    struct audioformat *fp)

{

err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs,

  stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0,

  stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1,

  &pcm);

}

static int _snd_pcm_new(struct snd_card *card, const char *id, int device,

int playback_count, int capture_count, bool internal,

struct snd_pcm **rpcm)

{

struct snd_pcm *pcm;

int err;

static struct snd_device_ops ops = {

.dev_free = snd_pcm_dev_free,

.dev_register = snd_pcm_dev_register,

.dev_disconnect = snd_pcm_dev_disconnect,

};

if (snd_BUG_ON(!card))

return -ENXIO;

if (rpcm)

*rpcm = NULL;

pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);

if (pcm == NULL) {

snd_printk(KERN_ERR "Cannot allocate PCM\n");

return -ENOMEM;

}

pcm->card = card;

pcm->device = device;

pcm->internal = internal;

}

static int snd_pcm_dev_register(struct snd_device *device)

{

int cidx, err;

struct snd_pcm_substream *substream;

struct snd_pcm_notify *notify;

char str[16];

struct snd_pcm *pcm;

struct device *dev;

if (snd_BUG_ON(!device || !device->device_data))

return -ENXIO;

pcm = device->device_data;

mutex_lock(®ister_mutex);

err = snd_pcm_add(pcm);

if (err) {

mutex_unlock(®ister_mutex);

return err;

}

for (cidx = 0; cidx < 2; cidx++) {

int devtype = -1;

if (pcm->streams[cidx].substream == NULL || pcm->internal)

continue;

switch (cidx) {

case SNDRV_PCM_STREAM_PLAYBACK:

sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);

devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;

break;

case SNDRV_PCM_STREAM_CAPTURE:

sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);

devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;

break;

}

/* device pointer to use, pcm->dev takes precedence if

* it is assigned, otherwise fall back to card's device

* if possible */

dev = pcm->dev;

if (!dev)

dev = snd_card_get_device_link(pcm->card);

/* register pcm */

err = snd_register_device_for_dev(devtype, pcm->card,

  pcm->device,

  &snd_pcm_f_ops[cidx],

  pcm, str, dev);

if (err < 0) {

list_del(&pcm->list);

mutex_unlock(®ister_mutex);

return err;

}

snd_add_device_sysfs_file(devtype, pcm->card, pcm->device,

  &pcm_attrs);

for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)

snd_pcm_timer_init(substream);

}

list_for_each_entry(notify, &snd_pcm_notify_list, list)

notify->n_register(pcm);

mutex_unlock(®ister_mutex);

return 0;

}

最终会在: /dev/snd/pcm*   创建出节点。

进入framework/base/services/usb/java/com/android/server/usb/UsbAlsaManager.java

private static final String ALSA_DIRECTORY = "/dev/snd/";

private final FileObserver mAlsaObserver = new FileObserver(ALSA_DIRECTORY,

            FileObserver.CREATE | FileObserver.DELETE) {

        public void onEvent(int event, String path) {

            switch (event) {

                case FileObserver.CREATE:

                    alsaFileAdded(path);

                    break;

                case FileObserver.DELETE:

                    alsaFileRemoved(path);

                    break;

            }

        }

    };

当/dev/snd/目录下有新的设备节点创建时调用:alsaFileAdded()

private void alsaFileAdded(String name) {

        int type = AlsaDevice.TYPE_UNKNOWN;

        int card = -1, device = -1;

        if (name.startsWith("pcmC")) {

            if (name.endsWith("p")) {

                type = AlsaDevice.TYPE_PLAYBACK;

            } else if (name.endsWith("c")) {

                type = AlsaDevice.TYPE_CAPTURE;

            }

        } else if (name.startsWith("midiC")) {

            type = AlsaDevice.TYPE_MIDI;

        }

        if (type != AlsaDevice.TYPE_UNKNOWN) {

            try {

                int c_index = name.indexOf('C');

                int d_index = name.indexOf('D');

                int end = name.length();

                if (type == AlsaDevice.TYPE_PLAYBACK || type == AlsaDevice.TYPE_CAPTURE) {

                    // skip trailing 'p' or 'c'

                    end--;

                }

                card = Integer.parseInt(name.substring(c_index + 1, d_index));

                device = Integer.parseInt(name.substring(d_index + 1, end));

            } catch (Exception e) {

                Slog.e(TAG, "Could not parse ALSA file name " + name, e);

                return;

            }

            synchronized(mAlsaDevices) {

                if (mAlsaDevices.get(name) == null) {

                    AlsaDevice alsaDevice = new AlsaDevice(type, card, device);

                    Slog.d(TAG, "Adding ALSA device " + alsaDevice);

                    mAlsaDevices.put(name, alsaDevice);

                    mAlsaDevices.notifyAll();

                }

            }

        }

    }

最后会调到:usbDeviceAdded()

void usbDeviceAdded(UsbDevice usbDevice) {

...................................

ArrayList prevScanRecs = mCardsParser.getScanRecords();

mCardsParser.scan();

/*

mCardsParser.scan()的时候会读取声卡生成记录系统有多少逻辑设备的文件:/proc/asound/cards

cat  /proc/asound/cards 信息如下:

 0 [msm8939sndcards]: msm8939-snd-car - msm8939-snd-card-skuk

                                             msm8939-snd-card-skuk

1 [C170          ]: USB-Audio - Webcam C170

                          Webcam C170 at usb-msm_hsusb_host-1.4.1, high speed

public void scan() {

if (DEBUG) { Slog.i(TAG, "AlsaCardsParser.scan()"); } mCardRecords = new ArrayList();

        File cardsFile = new File(kCardsFilePath); //kCardsFilePath=/proc/asound/cards

        try {

            FileReader reader = new FileReader(cardsFile);

            BufferedReader bufferedReader = new BufferedReader(reader);

            String line = "";

            while ((line = bufferedReader.readLine()) != null) {

                AlsaCardRecord cardRecord = new AlsaCardRecord();

                cardRecord.parse(line, 0);

                line = bufferedReader.readLine();

                if (line == null) {

                    break;

                }

                cardRecord.parse(line, 1);

                mCardRecords.add(cardRecord);

            }

            reader.close();

        } catch (FileNotFoundException e) {

            e.printStackTrace();

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

*/

..................................

if (mCardsParser.isCardUsb(addedCard)) {

            UsbAudioDevice audioDevice = selectAudioCard(addedCard);

            if (audioDevice != null) {

                mAudioDevices.put(usbDevice, audioDevice);

            }

..................................

}

UsbAudioDevice selectAudioCard(int card) {

..................................

notifyDeviceState(audioDevice, true);

...................................

}

private void notifyDeviceState(UsbAudioDevice audioDevice, boolean enabled) {

...........................

// Capture Device

            if (audioDevice.mHasCapture) {

              int device = (audioDevice == mAccessoryAudioDevice ?

                        AudioSystem.DEVICE_IN_USB_ACCESSORY :

                        AudioSystem.DEVICE_IN_USB_DEVICE);

                mAudioService.setWiredDeviceConnectionState(

                        device, state, address, audioDevice.mDeviceName, TAG);

            }

...........................

}

frameworks/base/services/core/java/com/android/server/audio/AudioService.java

public void setWiredDeviceConnectionState(int type, int state, String address, String name,

            String caller) {

        synchronized (mConnectedDevices) {

            int delay = checkSendBecomingNoisyIntent(type, state);

            queueMsgUnderWakeLock(mAudioHandler,

                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,

                    0,

                    0,

                    new WiredDeviceConnectionState(type, state, address, name, caller),

                    delay);

        }

    }

public void handleMessage(Message msg) {

..............................

case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:

                    {  WiredDeviceConnectionState connectState =

                            (WiredDeviceConnectionState)msg.obj;

                        onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,

                                connectState.mAddress, connectState.mName, connectState.mCaller);

                        mAudioEventWakeLock.release();

                    }

                    break;

..............................

}

private void onSetWiredDeviceConnectionState(int device, int state, String address,

            String deviceName, String caller) {

.............................................................

boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||

                            (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&

                            ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));

            if (!handleDeviceConnection(state == 1, device, address, deviceName)) {

                // change of connection state failed, bailout

                return;

            }


............................................................


}


private boolean handleDeviceConnection(boolean connect, int device, String address,

            String deviceName) {

........................................


if (connect && !isConnected) {//第一次连接走这里

                final int res = AudioSystem.setDeviceConnectionState(device,

                        AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);

                if (res != AudioSystem.AUDIO_STATUS_OK) {

                    Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +

                            " due to command error " + res );

                    return false;

                }

                mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));

                return true;

            } else if (!connect && isConnected) {//断开走这里

                AudioSystem.setDeviceConnectionState(device,

                        AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);

                // always remove even if disconnection failed

                mConnectedDevices.remove(deviceKey);

                return true;

            }

..........................................

}

frameworks/base/media/java/android/media/AudioSystem.java

public static native int setDeviceConnectionState(int device, int state,

                                                      String device_address, String device_name);

通过JNI调到:frameworks/base/core/jni/android_media_AudioSystem.cpp

static jintandroid_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name){ const char *c_address = env->GetStringUTFChars(device_address, NULL); const char *c_name = env->GetStringUTFChars(device_name, NULL); int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast(device), static_cast(state),

                                          c_address, c_name));

    env->ReleaseStringUTFChars(device_address, c_address);

    env->ReleaseStringUTFChars(device_name, c_name);

    return (jint) status;

}

frameworks/av/media/libmedia/AudioSystem.cpp

status_t AudioSystem::setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address, const char *device_name){ const sp& aps = AudioSystem::get_audio_policy_service();

    const char *address = "";

    const char *name = "";

    if (aps == 0) return PERMISSION_DENIED;

    if (device_address != NULL) {

        address = device_address;

    }

    if (device_name != NULL) {

        name = device_name;

    }

    return aps->setDeviceConnectionState(device, state, address, name);

}

最终调到:

hardware\qcom\audio\policy_hal\AudioPolicyManager.cpp

status_t AudioPolicyManagerCustom::setDeviceConnectionStateInt(audio_devices_t device,

                                                        audio_policy_dev_state_t state,

                                                        const char *device_address,

                                                        const char *device_name)

{


..........................................................

// handle input devices if (audio_is_input_device(device)) { SortedVectorinputs; ssize_t index = mAvailableInputDevices.indexOf(devDesc); switch (state) { // handle input device connection case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: { if (index >= 0) { ALOGW("setDeviceConnectionState() device already connected: %d", device); return INVALID_OPERATION; } sp module = mHwModules.getModuleForDevice(device);

            if (module == NULL) {

                ALOGW("setDeviceConnectionState(): could not find HW module for device %08x",

                      device);

                return INVALID_OPERATION;

            }

            if (checkInputsForDevice(devDesc, state, inputs, devDesc->mAddress) != NO_ERROR) {

                return INVALID_OPERATION;

            }

            index = mAvailableInputDevices.add(devDesc);//添加到可用输入设备列表中待选

            if (index >= 0) {

                mAvailableInputDevices[index]->attach(module);

            } else {

                return NO_MEMORY;

            }

            // Set connect to HALs

            AudioParameter param = AudioParameter(devDesc->mAddress);

            param.addInt(String8(AUDIO_PARAMETER_DEVICE_CONNECT), device);

            mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString());

            // Propagate device availability to Engine

            mEngine->setDeviceConnectionState(devDesc, state);

        } break;


..........................................................

}

没有插入USB麦克风是输入设备列表LOG如下:

APM::Devices: Device id:5 type:0x80000004:Built-In Mic, addr:

APM::AudioPort:    Port[nm:, type:1, role:1]

APM::Devices: Device id:6 type:0x80000080:Built-In Back Mic, addr:

APM::AudioPort:    Port[nm:, type:1, role:1]

APM::Devices: Device id:9 type:0x80000100:Reroute Submix In, addr:0

APM::AudioPort:    Port[nm:, type:1, role:1]

APM::Devices: Device id:7 type:0x80000040:Telephony Rx, addr:

APM::AudioPort:    Port[nm:, type:1, role:1]

APM::Devices: Device id:8 type:0x80002000:FM Tuner In, addr:

APM::AudioPort:    Port[nm:, type:1, role:1]

当插入USB麦克风是输入设备列表LOG如下:

APM::Devices: Device id:5 type:0x80000004:Built-In Mic, addr:

APM::AudioPort:    Port[nm:, type:1, role:1]

APM::Devices: Device id:6 type:0x80000080:Built-In Back Mic, addr:

APM::AudioPort:    Port[nm:, type:1, role:1]

APM::Devices: Device id:9 type:0x80000100:Reroute Submix In, addr:0

APM::AudioPort:    Port[nm:, type:1, role:1]

APM::Devices: Device id:7 type:0x80000040:Telephony Rx, addr:

APM::AudioPort:    Port[nm:, type:1, role:1]

APM::Devices: Device id:8 type:0x80002000:FM Tuner In, addr:

APM::AudioPort:    Port[nm:, type:1, role:1]

APM::Devices: Device id:13 type:0x80001000:USB Device In, addr:card=1;device=0;

APM::AudioPort: Port[nm:USB-Audio - Webcam C170, type:1, role:1]

-----------------------------------------------------------------------------------------------------------------------

当APP通过:audioRecord =new AudioRecord(MediaRecorder.AudioSource.MIC, frequency,

        channelConfiguration, audioEncoding, recBufSize);

         audioRecord.startRecording();

最终会转到


status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,

                                            audio_io_handle_t *input,

                                            audio_session_t session,

                                            uid_t uid,

                                            uint32_t samplingRate,

                                            audio_format_t format,

                                            audio_channel_mask_t channelMask,

                                            audio_input_flags_t flags,

                                            audio_port_handle_t selectedDeviceId,

                                            input_type_t *inputType)

{

。。。。。。。。。。。。。。。

//根据输入源类型我们在app中选择的是inputSource=MediaRecorder.AudioSource.MIC

device = getDeviceAndMixForInputSource(inputSource, &policyMix);

。。。。。。。

}


audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource,AudioMix **policyMix)

{

    audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;

    audio_devices_t selectedDeviceFromMix =

          mPolicyMixes.getDeviceAndMixForInputSource(inputSource, availableDeviceTypes, policyMix);

    if (selectedDeviceFromMix != AUDIO_DEVICE_NONE) {

        return selectedDeviceFromMix;

    }

    return getDeviceForInputSource(inputSource);

}

audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource){ for (size_t routeIndex = 0; routeIndex < mInputRoutes.size(); routeIndex++) { sp route = mInputRoutes.valueAt(routeIndex);

        if (inputSource == route->mSource && route->isActive()) {

            return route->mDeviceDescriptor->type();

        }

    }

    return mEngine->getDeviceForInputSource(inputSource);

}



audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) const

{

。。。。。。。。。。。

switch (inputSource) {

    case AUDIO_SOURCE_VOICE_UPLINK:

      if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {

          device = AUDIO_DEVICE_IN_VOICE_CALL;

          break;

      }

      break;

    case AUDIO_SOURCE_DEFAULT:

    case AUDIO_SOURCE_MIC:

    if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {

        device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;

    } else if ((mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO) &&

        (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {

        device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;

    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {

        device = AUDIO_DEVICE_IN_WIRED_HEADSET;

    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {

        device = AUDIO_DEVICE_IN_USB_DEVICE;

    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {

        device = AUDIO_DEVICE_IN_BUILTIN_MIC;

    }

    break;

。。。。。。。。

}

从次可以看出系统选择麦克风的优先顺序

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • 一.声音参数基本概念: 声音是连续模拟量,计算机将它离散化之后用数字表示,就有了以下几个名词术语。 样本长度(sa...
    cs1001阅读 2,698评论 0 2
  • USB设备驱动程序用来驱动相应的USB设备,USB设备驱动用usb_driver表示,它主要用来将USB设备挂接到...
    Joe_HUST阅读 6,160评论 1 5
  • 1.1PAD作为USB Device设备 USB Device的功能很丰富,其支持的协议越来越多包括:MTP、AD...
    android之子阅读 18,531评论 0 14
  • #include#include#include#include#include//#include "stdio...
    cs1001阅读 853评论 2 0
  • 我是这样一个人,对一切跟自己不同的人,特别是比我厉害的人都特别的好奇,甚至会盲目的崇拜,就是会特别的激动,特别想和...
    迷妹属性阅读 228评论 0 0