PDA

View Full Version : سوال: مشکل در بخش صدا بوسیله KDTele



morteza271
پنج شنبه 08 تیر 1391, 08:59 صبح
سلام.

من دارم یه برنامه شبیه برنامه منشی تلفنی مینویسم و برای این کار یه مودم خریدم.
حالا وقتی میخوام به وسیله مودم در خط تلفن صدا بخش کنم خطای زیر رو میده!کسی میدونه مشکلش چیه و باید چیکار کنم؟
متن خطا : Sound devise is exclusively allocated by another application.
اینم تصویر خطا :
88862

البته اینم بگم که از کامپوننت KDTele استفاده میکنم و با استفاده از تابع های AxKDVoice صدا رو بخش میکنم.
ممنون میشم اگه کمکم کنید.
با تشکر...

Saeed_m_Farid
پنج شنبه 08 تیر 1391, 09:58 صبح
سلام، بازم من:لبخند:
مشکلش که مشخصه چیه: شما یه جایی پورت مودم‌اِت رو باز نگهداشتی، حالا سعی می‌کنی از همون پورت دوباره استفاده کنی...
=====================
با اینکه میدونم بازم راه به ناکجاآباد (http://barnamenevis.org/showthread.php?343302#post1515432) می‌بریم، ولی خوب!
* تو کدوم state‌ (در OnCallState) میخوای صدا بخش کنی؟ فرض کنیم در KDTele.TxCallState.csConnected شما میخواین صدا پخش کنید و چون Answering Machine (منشی تلفنی) می‌نویسین، پس Dial نکردین! حالا قبل از پخش پیغام یه Sleep یک ثانیه‌ای (حداقل! چون مشتری نمی‌میره مثلاً دو ثانیه بعد جوابش رو بشنوه، ولی برنامه شما -مخصوصاً که با KDTele نوشته شده!- ممکنه بمیره) بذارید و بعدش پیغام رو پخش کنید؛ مثلاً همچین کدی:
case KDTele.TxCallState.csConnected://after answer
System.Threading.Thread.Sleep(1500);
int result =
KDVoice1.Play(KDPhone1.WavePlayID,
Application.StartupPath + @"\MyMessage.wav",
0,
-1);
if (result != 0)
//Handle an error log...
break;

در ضمن مطمئن بشین که در OnSoundState و رویداد ssPlayDone وقتی شما کلاً کارتون با مشترک تموم شد (که باید در یه State عمومی نگه داشته باشید!)، KDPhone رو Hangup کرده باشید...
_____________________
این ساده‌ترین حالت Answering Machine بود؛ اگه شما حالت خاصی در پروژه‌تون دارین، ذکر کنید.

morteza271
پنج شنبه 08 تیر 1391, 10:35 صبح
ممنونم دوست عزیز.
برنامه من به این شکله که مشتری زنگ میزنه و سیستم به صورت خودکار تلفن رو صل میکنه و یه پیامی رو بخش میکنه!و بعد با دریافت چند کلید از کاربر یه پیام دیگه رو بخش میکنه همین.

در دریافت تماس و وصل کردن آن مشکلی نیست و ندارم فقط وقتی که میخوام پیام رو بخش کنم این پیام رو میده!!
من کدم به این شکله که بعد در State مربوط به تماس دیافتی یعنی csRing یک تابع را فراخوانی میکنم که کار این تابع به این صورته که :
اول تماس رو وصل میکنه با متد Answer
بعد یه پیام رو بخش میکنه با همون کدی که شما گذاشتین
و بعد از بخش پیام منتظر دریافت کلید میمونه
بعد از دریافت کلید یه پیام دیگه بخش میکنه و بعد تماس رو قطع میکنه همین!

این چند کار در تابعی که در حالت csRing صدا زده میشه انجام میشه! حالا شما بگین که آیا روش درسته و یا اینکه مشکل از روشمه!!
ممنون میشم کمکم کنید باید شنبه برنامه رو تحویل بدم!!!

morteza271
پنج شنبه 08 تیر 1391, 11:57 صبح
از دوستان دیگه کسی این مشکل رو نمیدونه چجوری برطرف میشه؟؟

Saeed_m_Farid
پنج شنبه 08 تیر 1391, 12:00 عصر
من کدم به این شکله که بعد در State مربوط به تماس دیافتی یعنی csRing یک تابع را فراخوانی میکنم که کار این تابع به این صورته که :
اول تماس رو وصل میکنه با متد Answer
بعد یه پیام رو بخش میکنه با همون کدی که شما گذاشتین
و بعد از بخش پیام منتظر دریافت کلید میمونه
بعد از دریافت کلید یه پیام دیگه بخش میکنه و بعد تماس رو قطع میکنه همین!

این چند کار در تابعی که در حالت csRing صدا زده میشه انجام میشه! حالا شما بگین که آیا روش درسته و یا اینکه مشکل از روشمه!!
حالا ما می‌گیم که نه، روش شما غلط هست؛ چرا؟
===============
شما دید State machine ندارین:

http://sourcemaking.com/files/sm/images/patterns/State1.gif


+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
نمیشه همه اون کارها رو در یک تابع انجام داد، یعنی دید تابعی رو باید بذارید کنار، شما نسبت به هر event باید به state بعدی برین و هر عملی رو باید بصورت مجزا انجام بدین، یعنی با توجه به اطلاعات شما:


یه متغیر سراسری مثلاً بنام CallState تعریف کنید، ازنظر من بهتره enum باشه ولی می‌تونین int هم تعریف کنید (چون عجله دارین، من همین رو درنظر می‌گیرم!) و مقدارش رو برای شروع کار 0 بدین...
اول که تماس رو وصل می‌کنید (اصولاً بین Ring اول و دوم): یعنی csOffering و اگه csOfferedCallDropped اومد یعنی یه مشکلی پیش اومده یا طرف تک زنگ زده! و ... (دیگه شما با csRing کاری ندارین، مگه اینکه مطمئن بشید که هیچوقت csOffering یا csOfferedCallDropped نمیان؛ اونوقت هم باید ببینید چندمین زنگ هست (با IKDPhoneEvents_OnCallStateEvent)، بعدش Answer کنید؛ و بهتره بعد زنگ دوم بردارین، چون مخابرات ما مزخرف هست، حال میکنن بعد زنگ دوم CallerID بفرستن...) اگه csOffering یا csRing اومد و شما موفقیت آمیز Answer کردین، CallState میشه مثلاً 10!
مثل کد ما نشد! من گفتم باید وقتی Event مربوط به csConnected اومد، شما Play کنید نه اینکه تو یه تابع اونم در event مربوط به csRing... پس: شما در رویداد csConnected اگه CallState برابر با 10 بود (مرحله قبل موفقیت آمیز بود)، پس شما می تونید پیام رو پخش کنید و بازم اگه موفقیت آمیز Play کردین، CallState رو بکنید 20
حالا باید برای OnDigitDetected یک کد بنویسید که حاوی الگوریتم گرفتن DTMF (همون کلیدهای روی شاسی تلفن!) شما هست؛ مثلاً در ساده ترین حالت، اگه e.digit (از نوع IKDPhoneEvents_OnDigitDetectedEvent) معادل کلید موردنظر شما بود و CallState برابر با 40 بود (در قسمت بعدی میگم چرا!)، یه پیام دیگه بخش میکنه و اگه موفقیت آمیز Play کردین، CallState رو بکنید 30 [1]
کد بعدی شما باید در OnSoundState و رویداد ssPlayDone نوشته بشه، که یه switch میذارید برای CallState: اگه 20 بود CallState میشه 40 و اگه 30 بود ()KDPhone1.Hangup و CallState رو بازم می‌کنید 0 تا برگردید به حالت اول ... [2]

________________________
[1] اکثر اوقات یه کلید DTMF نمیگیرن و معمولاً گرفتن * یا # یا مثلاً n رقم (یا رسیدن Timeoute) نشانه پایان عملیات هست؛ پس شما باید برای اینکه چنین حالتی رو پیاده کنید، کدی مثل این بنویسین‌ (10=n):
if (e.digit == "*" || e.digit == "#")
{
if (userEntry == OUR_DESIRED_STREAM)
{
CallState = 1;
playResult =
KDVoice1.Play(
KDPhone1.WavePlayID,
Application.StartupPath + @"\RightEntry.wav",
0, -1);
if (playResult == 0)
//Handle an error log...
CallState = 30;
}
else
{
userEntry = "";//no wait
CallState = 100;
playResult =
KDVoice1.Play(
KDPhone1.WavePlayID,
Application.StartupPath + @"\WrongEntry.wav",
0, -1);
if (playResult != 0)
//Handle an error log...
}
userEntry = String.Empty;
CallState = 30;
}
else
{
userEntry = userEntry + e.digit;
if (userEntry.Length > 10)
{
playResult =
KDVoice1.Play(
KDPhone1.WavePlayID,
Application.StartupPath + @"\WrongEntry.wav",
0, -1);
if (playResult != 0)
//Handle an error log...
CallState = 30;
}
}

[2] این ساده ترین حالت هست، من نمیدونم KDTele با چه Thread ای و چطور کار میکنه، ولی باور کنید این کد فقط واسه اینه که کارتون تا رابه راه بیافته و من کماکان روی نظرم (http://barnamenevis.org/showthread.php?343302#post1515432) هستم!
[3] نمیخوام اذیتت کنم و معلومات و ... ولی جداً توصیه می‌کنم الگوهای طراحی State Pattern رو ببینی؛ برای نمونه : Observer Pattern (http://www.oodesign.com/observer-pattern.html) و Memento Pattern (http://www.oodesign.com/memento-pattern.html)؛ به مشکل خوردم که میگم، اونم جدی...

morteza271
پنج شنبه 08 تیر 1391, 12:20 عصر
ممنونم دوست عزیز، خیلی لطف دارین که وقت میذارین و جواب میدین!

یه نمونه کد ندارین که بتونم راحت تر کارمو انجام بدم، چون عجله ای میگم وگرنه یه کاریش میکردم...
بازم ممنونم...